Why is #include <stdio.h> not required to use printf()?
Asked Answered
I

3

34

Session transcript:

> type lookma.c
int main() {
  printf("%s", "no stdio.h");
}

> cl lookma.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

lookma.c
Microsoft (R) Incremental Linker Version 8.00.50727.762
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:lookma.exe
lookma.obj

> lookma
no stdio.h
Inoffensive answered 3/12, 2008 at 10:57 Comment(2)
Note that in C89/C90, you should supply a return value from main(). C99 allows you to omit return 0; or equivalent from the end of main().Taxeme
In what context? Command line window on Windows?Soonsooner
T
35

In strict compliance mode (that means "in theory"), you invoke undefined behaviour (which is bad) when you call a function that takes a variable number of arguments without a prototype declaration of the function in scope. That means that the compiler is allowed to do anything it likes with a program that uses printf() without the prototype from #include <stdio.h> or an equivalent declaration. "Anything it likes" includes working correctly as one of the options; that seems to be the option chosen by your example.

In practice, the code will work OK with most practical compilers even without the formal declaration of the printf() function.

As was pointed out by qrdl, the function was found because the C compiler links with the C library.

Note that Chris Young's comment about C99 and 'implicit int' is accurate, but the rule about 'variable arguments functions must have a prototype in scope' applies to both C89 and C99. Most compilers do not work in a strict C99 compatibility mode by default because there is too much code that would not compile like that.

Chris Young commented:

To clarify, my comment was on C99 removing implicit declarations. By saying "implicit int", I think you are referring to the C89 feature of allowing declarations such as foo(void); to mean int foo(void);, something C99 also removed.

Chris is, of course, correct. There were two 'implicit declaration' features removed from the C99 standard. The foreword to the standard lists them as:

  • remove implicit int
  • remove implicit function declaration

I was not thinking (and hence not writing) clearly enough. Nevertheless, both C89 and C99 require a prototype in scope for functions that take a variable number of arguments.

To illustrate:

extern int pqr();
int main(void)
{
    int i = pqr(1, 3);
    return i;
}

Without the first line, this is a correct C89 fragment with an implicit declaration of the function pqr() as a function that returns an integer (with unspecified arguments). If the first line is replaced by extern pqr();, then this is a correct C89 fragment with an explicit declaration of pqr() as a function that returns an integer (with unspecified arguments), but the return type is 'implicit int'. As written, the function is explicitly declared and has an explicit int return type - but it still has unspecified arguments. I believe that is valid C99 - albeit not wholly desirable. Certainly, GCC (3.4.4) accepts it with the options '-std=c99 -pedantic". Ideally, the function declaration should include the full prototype. (And, if pqr() were defined with ellipsis, that prototype would be required in theory!)

Taxeme answered 4/12, 2008 at 20:37 Comment(1)
To clarify, my comment was on C99 removing implicit delcarations. By saying "implicit int", I think you are referring to the C89 feature of allowing declarations such as foo(void); to mean int foo(void);, something C99 also removed.Keikokeil
K
40

You had originally tagged this C++, but it would appear to be a C program. C will automatically provide an implicit declaration for a function if there is no prototype in scope (such as due to the omission of #include <stdio.h>). The implicit declaration would be:

int printf();

Meaning that printf is a function that returns an int and can take any number of arguments. This prototype happened to work for your call. You should #include <stdio.h>

Finally, I should add that the current C standard (ISO/IEC 9899:1999 or colloquially "C99") does not allow implicit declarations, and this program would not conform. Implicit declarations were removed. I believe your compiler does not support C99. C++ also requires correct prototypes and does not do implicit declarations.

Keikokeil answered 3/12, 2008 at 11:1 Comment(0)
T
35

In strict compliance mode (that means "in theory"), you invoke undefined behaviour (which is bad) when you call a function that takes a variable number of arguments without a prototype declaration of the function in scope. That means that the compiler is allowed to do anything it likes with a program that uses printf() without the prototype from #include <stdio.h> or an equivalent declaration. "Anything it likes" includes working correctly as one of the options; that seems to be the option chosen by your example.

In practice, the code will work OK with most practical compilers even without the formal declaration of the printf() function.

As was pointed out by qrdl, the function was found because the C compiler links with the C library.

Note that Chris Young's comment about C99 and 'implicit int' is accurate, but the rule about 'variable arguments functions must have a prototype in scope' applies to both C89 and C99. Most compilers do not work in a strict C99 compatibility mode by default because there is too much code that would not compile like that.

Chris Young commented:

To clarify, my comment was on C99 removing implicit declarations. By saying "implicit int", I think you are referring to the C89 feature of allowing declarations such as foo(void); to mean int foo(void);, something C99 also removed.

Chris is, of course, correct. There were two 'implicit declaration' features removed from the C99 standard. The foreword to the standard lists them as:

  • remove implicit int
  • remove implicit function declaration

I was not thinking (and hence not writing) clearly enough. Nevertheless, both C89 and C99 require a prototype in scope for functions that take a variable number of arguments.

To illustrate:

extern int pqr();
int main(void)
{
    int i = pqr(1, 3);
    return i;
}

Without the first line, this is a correct C89 fragment with an implicit declaration of the function pqr() as a function that returns an integer (with unspecified arguments). If the first line is replaced by extern pqr();, then this is a correct C89 fragment with an explicit declaration of pqr() as a function that returns an integer (with unspecified arguments), but the return type is 'implicit int'. As written, the function is explicitly declared and has an explicit int return type - but it still has unspecified arguments. I believe that is valid C99 - albeit not wholly desirable. Certainly, GCC (3.4.4) accepts it with the options '-std=c99 -pedantic". Ideally, the function declaration should include the full prototype. (And, if pqr() were defined with ellipsis, that prototype would be required in theory!)

Taxeme answered 4/12, 2008 at 20:37 Comment(1)
To clarify, my comment was on C99 removing implicit delcarations. By saying "implicit int", I think you are referring to the C89 feature of allowing declarations such as foo(void); to mean int foo(void);, something C99 also removed.Keikokeil
I
11

printf() is located in the standard C library and the linker always links the standard library to your executable, so any standard functions will be found and there will be no linking problems.

Failure to include the appropriate header results in using a function that wasn't prototyped that can lead to problems, as the C compiler assumes that a function without a prototype returns int and takes a variable number of arguments. So always include the header - it's your safety fence.

Itching answered 3/12, 2008 at 11:16 Comment(1)
Not a 'variable number of arguments' but an undefined-but-fixed number of arguments.Taxeme

© 2022 - 2024 — McMap. All rights reserved.