c++gcciostreamstdio

Dealing with bycatch of <stdio.h> definitions caused by C++ includes


In a comment to another answer, I was shown a code example that seemingly used printf and puts without including <stdio.h> but the online compiler didn't complain.[1] To understand what's going on, I copied it to my local IDE.

Reduced to relevant includes and output, it's basically this:

#include <string>
#include <map>
#include <optional>

int main() {
  printf("Answer %d\n", 42);
  puts("Question?");
}

Experimenting with gcc 8.1.0 (packaged with Code::Blocks 20.03), I found out, that the includes can be further reduced to

Also, a sample test — C++14 (GCC 8.3) — on ideone.com compiles and runs fine:

#include <iostream>

int main() {
    printf("printf without #include <stdio.h>\n");
    return 0;
}

This is also true for other definitions from <stdio.h> like FILE.

I found no information at cppreference.com

I also tried several web and SO searches but wasn't successful so far.

While it may be handy for small examples to get some powerful functions for free, but a serious project may suffer from it: besides comparatively easy to fix compiler errors, I see the danger of serious runtime errors.

How can I effectively control/prevent this kind of inclusion?

2024 Update:

Even today we can observe this behaviour in GCC 13.2:

#include <string>

int main() {
    printf("Hello ");
    puts("world!");
}

No complains when compiling above code via gcc -std=c++20 -Wall -Wextra -Wpedantic -Werror.


[1] the referenced code in fact containes the include statement, so I obviously didn't copy all the code. Anyway, the observed behavior is there as described above.


Solution

  • I am afraid you cannot.

    The standard requires that the well known include files declare the relevant names, but does not prevent them to include other files/names, if the library implementation finds it useful.

    Said differently, after including iostream you are sure that all the names belonging to it are correctly declared, but you cannot know (except by examining the file itself) if other names have been defined, or if other standard files have been included. Here, your implementation chooses to automatically include stdio.h, but a different (standard library) implementation could choose not to include it. You have reached the world of unspecifiedness...