I'm pretty new to C, and I know that static functions can only be used within the same object file. Something that still confuses me though, is how if I hover over a call to printf in my IDE it tells me that printf is a static function, when I can perfectly use printf in multiple object files without any problems? Why is that?
Edit: I'm using Visual Studio Code the library is stdio.h and compiling using GCC
#include <stdio.h>
int main()
{
printf("Hello, world!");
return 0;
}
Hovering over printf would give that hint
Edit 2: if static inline functions are different from inline functions how so? I don't see how making a function inline would change the fact that it's only accessible from the same translation unit
Edit 3: per request, here's the definition of printf
in the stdio.h
header
__mingw_ovr
__attribute__((__format__ (gnu_printf, 1, 2))) __MINGW_ATTRIB_NONNULL(1)
int printf (const char *__format, ...)
{
int __retval;
__builtin_va_list __local_argv; __builtin_va_start( __local_argv, __format );
__retval = __mingw_vfprintf( stdout, __format, __local_argv );
__builtin_va_end( __local_argv );
return __retval;
}
Thanks for all the updates. Your IDE is showing you implementation details of your C library that you're not supposed to have to worry about. That is arguably a bug in your IDE but there's nothing wrong with the C library.
You are correct to think that a function declared static
is visible only within the translation unit where it is defined. And that is true whether or not the function is also marked inline
. However, this particular static inline
function is defined inside stdio.h
, so every translation unit that includes stdio.h
can see it. (There is a separate copy of the inline in each TU. This is technically a conformance violation since, as chux surmises, it means that &printf
in one translation unit will not compare equal to &printf
in another. However, this is very unlikely to cause problems for a program that isn't an ISO C conformance tester.)
As "Adrian Mole" surmised in the comments on the question, the purpose of this inline function is, more or less, to rewrite
printf("%s %d %p", string, integer, pointer);
into
fprintf(stdout, "%s %d %p", string, integer, pointer);
(All the stuff with __builtin_va_start
and __mingw_vfprintf
is because of limitations in how variadic functions work in C. The effect is the same as what I showed above, but the generated assembly language will not be nearly as tidy.)
Update 2022-12-01: It's worse than "the generated assembly language will not be nearly as tidy". I experimented with all of the x86 compilers supported by godbolt.org and none of them will inline a function that takes a variable number of arguments, even if you try to force it. Most silently ignore the force-inlining directive; GCC gets one bonus point for actually saying it refuses to do this:
test.c:4:50: error: function ‘xprintf’ can never be inlined
because it uses variable argument lists
In consequence, every program compiled against this version of MinGW libc, in which printf
is called from more than one .c
file, will have multiple copies of the following glob of assembly embedded in its binary. This is bad just because of cache pollution; it would be better to have a single copy in the C library proper -- which is exactly what printf
normally is.
printf:
mov QWORD PTR [rsp+8], rcx
mov QWORD PTR [rsp+16], rdx
mov QWORD PTR [rsp+24], r8
mov QWORD PTR [rsp+32], r9
push rbx
push rsi
push rdi
sub rsp, 48
mov rdi, rcx
lea rsi, QWORD PTR f$[rsp+8]
mov ecx, 1
call __acrt_iob_func
mov rbx, rax
call __local_stdio_printf_options
xor r9d, r9d
mov QWORD PTR [rsp+32], rsi
mov r8, rdi
mov rdx, rbx
mov rcx, QWORD PTR [rax]
call __stdio_common_vfprintf
add rsp, 48
pop rdi
pop rsi
pop rbx
ret 0
(Probably not exactly this assembly, this is what godbolt's "x64 MSVC 19.latest" produces with optimization option /O2
, godbolt doesn't seem to have any MinGW compilers. But you get the idea.)