UBoiii
UBoiii

Reputation: 23

Is printf a static function in C?

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;
}

screenshot of the printf definition in my IDE

Upvotes: 2

Views: 548

Answers (2)

zwol
zwol

Reputation: 140826

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.)

Upvotes: 3

n. m. could be an AI
n. m. could be an AI

Reputation: 120079

__mingw_ovr is normally defined as

#define __mingw_ovr static __attribute__ ((__unused__)) __inline__ __cdecl

It appears that this definition of printf is a violation of the C standard. The standard says

7.1.2 Standard headers
6 Any declaration of a library function shall have external linkage

Upvotes: 1

Related Questions