| Home | Classes | Papers | Essays | Short Fiction | About |

CS211: (Appendix) #include and Macros

Table of Contents

Introduction

If you're reading this appendix chapter you've likely already encountered the use of the #include phrase in coding examples. You'd be hard pressed to find any C code that doesn't make use of that or other lines using the # symbol. This chapter aims to demystify what's going on when it and similar phrases are invoked.

#include Command

Every single time we've used printf we've included the line #include <stdio.h>. For example, even in a simple "hello world" program we use it—here's what happens if we don't:

1: int main(){
2:   printf("Hello, World!\n");
3: }
 1: josephraskind@stargazer:/tmp/macros$ gcc hello_world.c 
 2: hello_world.c: In function ‘main’:
 3: hello_world.c:2:3: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
 4:     2 |   printf("Hello, World!\n");
 5:       |   ^~~~~~
 6: hello_world.c:2:3: warning: incompatible implicit declaration of built-in function ‘printf’
 7: hello_world.c:1:1: note: include ‘<stdio.h>’ or provide a declaration of ‘printf’
 8:   +++ |+#include <stdio.h>
 9:     1 | int main(){
10: josephraskind@stargazer:/tmp/macros$ ./a.out 
11: Hello, World!

Why the warnings? Well, gcc actually has no issue compiling when a non-existant function is called—it essentially defers to the programmer that there really is a function called printf that will eventually be resolved at the linking stage. We can see what happens if I replace printf with the non-existant function printNOTREAL:

1: josephraskind@stargazer:/tmp/macros$ gcc hello_world.c 
2: hello_world.c: In function ‘main’:
3: hello_world.c:2:3: warning: implicit declaration of function ‘printNOTREAL’ [-Wimplicit-function-declaration]
4:     2 |   printNOTREAL("Hello, World!\n");
5:       |   ^~~~~~~~~~~~
6: /usr/bin/ld: /tmp/ccnimtjV.o: in function `main':
7: hello_world.c:(.text+0x15): undefined reference to `printNOTREAL'
8: collect2: error: ld returned 1 exit status

printNOTREAL isn't resolved, but printf is? What gives?

Well, let's take a look at what is actually called by gcc:

 1: josephraskind@stargazer:/tmp/macros$ gcc -v
 2: Using built-in specs.
 3: COLLECT_GCC=gcc
 4: COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper
 5: OFFLOAD_TARGET_NAMES=nvptx-none:hsa
 6: OFFLOAD_TARGET_DEFAULT=1
 7: Target: x86_64-linux-gnu
 8: Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.4.0-1ubuntu1~20.04.2' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-9-9QDOt0/gcc-9-9.4.0/debian/tmp-nvptx/usr,hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
 9: Thread model: posix
10: gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.2)

That's a lot of hidden configurations! The most instructive for us is Line 4 which shows the COLLECT_LTO_WRAPPER environment variable for Link Time Optimization. If we peek inside the binary file:

00000350: 2f6c 6962 3634 2f6c 642d 6c69 6e75 782d  /lib64/ld-linux-
00000360: 7838 362d 3634 2e73 6f2e 3200 0000 0000  x86-64.so.2.....

we see a reference to ld-linux-x86-64.so.2 which is the dynamic linker and loader for my Linux environment. Within the loader is a reference to printf, but there isn't an actual implementation. For that we can check the executable returned by gcc hello_world.c -o hello:

josephraskind@stargazer:/tmp/macros$ ldd ./hello
        linux-vdso.so.1 (0x00007fff485c8000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe54e8f2000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fe54eb07000)

ldd prints shared object dependencies, and we can see that the major dependency in our hello executable is libc.so.6 which does store a precompiled implementation of printf! Why all of this jumping around? Well, it turns out that by default gcc does something called dynamic linking where certain bits of code are only linked to in the executable instead of being baked into the executable itself. Why? Well lets dynamically link and statically link hello_world.c:

josephraskind@stargazer:/tmp/macros$ gcc hello_world.c -o hello_dynamic
josephraskind@stargazer:/tmp/macros$ gcc hello_world.c --static -o hello_static
josephraskind@stargazer:/tmp/macros$ ./hello_dynamic 
Hello, World!
josephraskind@stargazer:/tmp/macros$ ./hello_static
Hello, World!

They both work exactly the same…so what's the big deal? If we take a look at their sizes:

josephraskind@stargazer:/tmp/macros$ du -h ./hello_dynamic ./hello_static 
20K	./hello_dynamic
852K	./hello_static

We can see that the statically linked binary is 40x greater than the dynamically linked binary!

Header Files

What exactly is stdio.h? It is a header file which is just a regular C file that is specifically written to be included by different C files. There is nothing semantically special about header files. For example, I can define my own header file called cool_print.h:

 1: #include <stdio.h>
 2: #include <stdarg.h>
 3: 
 4: void cool_printf(const char *fmt, ...){
 5:   va_list args;         // Using variable argument list type
 6:   va_start(args, fmt);  
 7:   printf("cool: ");     // Preprinting "cool:" before calling real printf
 8:   vprintf(fmt, args);
 9:   va_end(args);         // Unwinding argument list
10: }

Then, in the same directory, I can define a new C file called using_cool_printf.c:

1: #include "cool_print.h"
2: 
3: int main(){
4:   cool_printf("Hello, World!\n");
5: }

Notice that I put double quotes around cool_print.h instead of angle brackets. Angle brackets are for header files that are stored in the standard library (see the macros section below for how that gets expanded). Double quotes are for relative or absolute file paths. We can compile and run the program:

josephraskind@stargazer:/tmp/macros$ gcc using_cool_print.c -o cool; ./cool
cool: Hello, World!

Again, if I don't use the include statement:

josephraskind@stargazer:/tmp/macros$ gcc using_cool_print.c -o cool
using_cool_print.c: In function ‘main’:
using_cool_print.c:4:3: warning: implicit declaration of function ‘cool_printf’ [-Wimplicit-function-declaration]
    4 |   cool_printf("Hello, World!\n");
      |   ^~~~~~~~~~~
/usr/bin/ld: /tmp/ccnBuSd7.o: in function `main':
using_cool_print.c:(.text+0x15): undefined reference to `cool_printf'
collect2: error: ld returned 1 exit status

Because cool_printf is not in the standard, dynamic linked binaries it cannot be linked and thus an executable cannot be created.

What happens if I include my header twice? Let's see:

1: #include "cool_print.h"
2: #include "cool_print.h"
3: 
4: int main(){
5:   cool_printf("Hello, World!\n");
6: }
josephraskind@stargazer:/tmp/macros$ gcc using_cool_print.c -o cool
In file included from using_cool_print.c:2:
cool_print.h:6:6: error: redefinition of ‘cool_printf’
    6 | void cool_printf(const char *fmt, ...){
      |      ^~~~~~~~~~~
In file included from using_cool_print.c:1:
cool_print.h:6:6: note: previous definition of ‘cool_printf’ was here
    6 | void cool_printf(const char *fmt, ...){
      |      ^~~~~~~~~~~

As we'll see later, include is essentially a simple copy-paste job of the header "into" the .c file. As detailed in the chapter on functions, we cannot define a function twice in C. This can be solved with a header guard (which you'll find on every standard library header file):

 1: #ifndef CS211_COOL_PRINT
 2: #define CS211_COOL_PRINT
 3: #include <stdio.h>
 4: #include <stdarg.h>
 5: 
 6: void cool_printf(const char *fmt, ...){
 7:   va_list args;         // Using variable argument list type
 8:   va_start(args, fmt);  
 9:   printf("cool: ");     // Preprinting "cool:" before calling real printf
10:   vprintf(fmt, args);
11:   va_end(args);         // Unwinding argument list
12: }
13: #endif

The guards check to see if the symbol CS211_COOL_PRINT exists. If it does, the macro will not be expanded; if it doesn't, the macro will be expaned. If we try the double include again:

josephraskind@stargazer:/tmp/macros$ gcc using_cool_print.c -o cool; ./cool
cool: Hello, World!

Now it works perfect!

Macros

Anytime you see the # symbol at the start of a C statement you're actually seeing something that exists outside the C Programming Language proper. You are looking at a macro. There are many macro directives, but in this class we're only concerned with define, include, ifdef, and endif:

  • define
    • Defines a macro symbol with content
    • #define SIZE 5 : Anytime SIZE is used it will be replaced with 5.
  • include
    • Will paste header file contents into the source code
    • #include <stdio.h> : Pastes all of the standard library stdio.h file into the host file
  • ifdef
    • Checks to see if a macro symbol has been defined already and will perform the next macro directive if true
  • endif
    • Terminates the matching ifdef directive

Let's look at a simple example:

1: #define VAL 10
2: int main(){
3:   return VAL;
4: }

We see here a macro definition for the symbol VAL which is tied to 10. If I run this code and capture the return value of the executable:

1: josephraskind@stargazer:/tmp/macros$ gcc val.c -o val; ./val; echo $?
2: 10

We can see that 10 was returned, just like what we defined. How does that work? Well, in gcc we can stop compilation at the macro expansion stage with gcc -E:

 1: josephraskind@stargazer:/tmp/macros$ gcc -E val.c
 2: # 1 "val.c"
 3: # 1 "<built-in>"
 4: # 1 "<command-line>"
 5: # 31 "<command-line>"
 6: # 1 "/usr/include/stdc-predef.h" 1 3 4
 7: # 32 "<command-line>" 2
 8: # 1 "val.c"
 9: 
10: int main(){
11:   return 10;
12: }

We can see that our VAL is gone completely and has been replaced by the number it was initially defined with! Let's see what happens with our basic hello_world.c:

  1: josephraskind@stargazer:/tmp/macros$ gcc -E hello_world.c
  2: # 1 "hello_world.c"
  3: # 1 "<built-in>"
  4: # 1 "<command-line>"
  5: # 31 "<command-line>"
  6: # 1 "/usr/include/stdc-predef.h" 1 3 4
  7: # 32 "<command-line>" 2
  8: # 1 "hello_world.c"
  9: # 1 "/usr/include/stdio.h" 1 3 4
 10: # 27 "/usr/include/stdio.h" 3 4
 11: # 1 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 1 3 4
 12: # 33 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 3 4
 13: # 1 "/usr/include/features.h" 1 3 4
 14: # 461 "/usr/include/features.h" 3 4
 15: # 1 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 1 3 4
 16: # 452 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 3 4
 17: # 1 "/usr/include/x86_64-linux-gnu/bits/wordsize.h" 1 3 4
 18: # 453 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 2 3 4
 19: # 1 "/usr/include/x86_64-linux-gnu/bits/long-double.h" 1 3 4
 20: # 454 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 2 3 4
 21: # 462 "/usr/include/features.h" 2 3 4
 22: # 485 "/usr/include/features.h" 3 4
 23: # 1 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 1 3 4
 24: # 10 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 3 4
 25: # 1 "/usr/include/x86_64-linux-gnu/gnu/stubs-64.h" 1 3 4
 26: # 11 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 2 3 4
 27: # 486 "/usr/include/features.h" 2 3 4
 28: # 34 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 2 3 4
 29: # 28 "/usr/include/stdio.h" 2 3 4
 30: 
 31: 
 32: 
 33: 
 34: 
 35: # 1 "/usr/lib/gcc/x86_64-linux-gnu/9/include/stddef.h" 1 3 4
 36: # 209 "/usr/lib/gcc/x86_64-linux-gnu/9/include/stddef.h" 3 4
 37: 
 38: # 209 "/usr/lib/gcc/x86_64-linux-gnu/9/include/stddef.h" 3 4
 39: typedef long unsigned int size_t;
 40: # 34 "/usr/include/stdio.h" 2 3 4
 41: 
 42: 
 43: # 1 "/usr/lib/gcc/x86_64-linux-gnu/9/include/stdarg.h" 1 3 4
 44: # 40 "/usr/lib/gcc/x86_64-linux-gnu/9/include/stdarg.h" 3 4
 45: typedef __builtin_va_list __gnuc_va_list;
 46: # 37 "/usr/include/stdio.h" 2 3 4
 47: 
 48: # 1 "/usr/include/x86_64-linux-gnu/bits/types.h" 1 3 4
 49: # 27 "/usr/include/x86_64-linux-gnu/bits/types.h" 3 4
 50: # 1 "/usr/include/x86_64-linux-gnu/bits/wordsize.h" 1 3 4
 51: # 28 "/usr/include/x86_64-linux-gnu/bits/types.h" 2 3 4
 52: # 1 "/usr/include/x86_64-linux-gnu/bits/timesize.h" 1 3 4
 53: # 29 "/usr/include/x86_64-linux-gnu/bits/types.h" 2 3 4
 54: 
 55: 
 56: typedef unsigned char __u_char;
 57: typedef unsigned short int __u_short;
 58: typedef unsigned int __u_int;
 59: typedef unsigned long int __u_long;
 60: 
 61: 
 62: typedef signed char __int8_t;
 63: typedef unsigned char __uint8_t;
 64: typedef signed short int __int16_t;
 65: typedef unsigned short int __uint16_t;
 66: typedef signed int __int32_t;
 67: typedef unsigned int __uint32_t;
 68: 
 69: typedef signed long int __int64_t;
 70: typedef unsigned long int __uint64_t;
 71: 
 72: 
 73: 
 74: 
 75: 
 76: 
 77: typedef __int8_t __int_least8_t;
 78: typedef __uint8_t __uint_least8_t;
 79: typedef __int16_t __int_least16_t;
 80: typedef __uint16_t __uint_least16_t;
 81: typedef __int32_t __int_least32_t;
 82: typedef __uint32_t __uint_least32_t;
 83: typedef __int64_t __int_least64_t;
 84: typedef __uint64_t __uint_least64_t;
 85: 
 86: 
 87: 
 88: typedef long int __quad_t;
 89: typedef unsigned long int __u_quad_t;
 90: 
 91: 
 92: 
 93: 
 94: 
 95: 
 96: 
 97: typedef long int __intmax_t;
 98: typedef unsigned long int __uintmax_t;
 99: # 141 "/usr/include/x86_64-linux-gnu/bits/types.h" 3 4
100: # 1 "/usr/include/x86_64-linux-gnu/bits/typesizes.h" 1 3 4
101: # 142 "/usr/include/x86_64-linux-gnu/bits/types.h" 2 3 4
102: # 1 "/usr/include/x86_64-linux-gnu/bits/time64.h" 1 3 4
103: # 143 "/usr/include/x86_64-linux-gnu/bits/types.h" 2 3 4
104: 
105: 
106: typedef unsigned long int __dev_t;
107: typedef unsigned int __uid_t;
108: typedef unsigned int __gid_t;
109: typedef unsigned long int __ino_t;
110: typedef unsigned long int __ino64_t;
111: typedef unsigned int __mode_t;
112: typedef unsigned long int __nlink_t;
113: typedef long int __off_t;
114: typedef long int __off64_t;
115: typedef int __pid_t;
116: typedef struct { int __val[2]; } __fsid_t;
117: typedef long int __clock_t;
118: typedef unsigned long int __rlim_t;
119: typedef unsigned long int __rlim64_t;
120: typedef unsigned int __id_t;
121: typedef long int __time_t;
122: typedef unsigned int __useconds_t;
123: typedef long int __suseconds_t;
124: 
125: typedef int __daddr_t;
126: typedef int __key_t;
127: 
128: 
129: typedef int __clockid_t;
130: 
131: 
132: typedef void * __timer_t;
133: 
134: 
135: typedef long int __blksize_t;
136: 
137: 
138: 
139: 
140: typedef long int __blkcnt_t;
141: typedef long int __blkcnt64_t;
142: 
143: 
144: typedef unsigned long int __fsblkcnt_t;
145: typedef unsigned long int __fsblkcnt64_t;
146: 
147: 
148: typedef unsigned long int __fsfilcnt_t;
149: typedef unsigned long int __fsfilcnt64_t;
150: 
151: 
152: typedef long int __fsword_t;
153: 
154: typedef long int __ssize_t;
155: 
156: 
157: typedef long int __syscall_slong_t;
158: 
159: typedef unsigned long int __syscall_ulong_t;
160: 
161: 
162: 
163: typedef __off64_t __loff_t;
164: typedef char *__caddr_t;
165: 
166: 
167: typedef long int __intptr_t;
168: 
169: 
170: typedef unsigned int __socklen_t;
171: 
172: 
173: 
174: 
175: typedef int __sig_atomic_t;
176: # 39 "/usr/include/stdio.h" 2 3 4
177: # 1 "/usr/include/x86_64-linux-gnu/bits/types/__fpos_t.h" 1 3 4
178: 
179: 
180: 
181: 
182: # 1 "/usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h" 1 3 4
183: # 13 "/usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h" 3 4
184: typedef struct
185: {
186:   int __count;
187:   union
188:   {
189:     unsigned int __wch;
190:     char __wchb[4];
191:   } __value;
192: } __mbstate_t;
193: # 6 "/usr/include/x86_64-linux-gnu/bits/types/__fpos_t.h" 2 3 4
194: 
195: 
196: 
197: 
198: typedef struct _G_fpos_t
199: {
200:   __off_t __pos;
201:   __mbstate_t __state;
202: } __fpos_t;
203: # 40 "/usr/include/stdio.h" 2 3 4
204: # 1 "/usr/include/x86_64-linux-gnu/bits/types/__fpos64_t.h" 1 3 4
205: # 10 "/usr/include/x86_64-linux-gnu/bits/types/__fpos64_t.h" 3 4
206: typedef struct _G_fpos64_t
207: {
208:   __off64_t __pos;
209:   __mbstate_t __state;
210: } __fpos64_t;
211: # 41 "/usr/include/stdio.h" 2 3 4
212: # 1 "/usr/include/x86_64-linux-gnu/bits/types/__FILE.h" 1 3 4
213: 
214: 
215: 
216: struct _IO_FILE;
217: typedef struct _IO_FILE __FILE;
218: # 42 "/usr/include/stdio.h" 2 3 4
219: # 1 "/usr/include/x86_64-linux-gnu/bits/types/FILE.h" 1 3 4
220: 
221: 
222: 
223: struct _IO_FILE;
224: 
225: 
226: typedef struct _IO_FILE FILE;
227: # 43 "/usr/include/stdio.h" 2 3 4
228: # 1 "/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h" 1 3 4
229: # 35 "/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h" 3 4
230: struct _IO_FILE;
231: struct _IO_marker;
232: struct _IO_codecvt;
233: struct _IO_wide_data;
234: 
235: 
236: 
237: 
238: typedef void _IO_lock_t;
239: 
240: 
241: 
242: 
243: 
244: struct _IO_FILE
245: {
246:   int _flags;
247: 
248: 
249:   char *_IO_read_ptr;
250:   char *_IO_read_end;
251:   char *_IO_read_base;
252:   char *_IO_write_base;
253:   char *_IO_write_ptr;
254:   char *_IO_write_end;
255:   char *_IO_buf_base;
256:   char *_IO_buf_end;
257: 
258: 
259:   char *_IO_save_base;
260:   char *_IO_backup_base;
261:   char *_IO_save_end;
262: 
263:   struct _IO_marker *_markers;
264: 
265:   struct _IO_FILE *_chain;
266: 
267:   int _fileno;
268:   int _flags2;
269:   __off_t _old_offset;
270: 
271: 
272:   unsigned short _cur_column;
273:   signed char _vtable_offset;
274:   char _shortbuf[1];
275: 
276:   _IO_lock_t *_lock;
277: 
278: 
279: 
280: 
281: 
282: 
283: 
284:   __off64_t _offset;
285: 
286:   struct _IO_codecvt *_codecvt;
287:   struct _IO_wide_data *_wide_data;
288:   struct _IO_FILE *_freeres_list;
289:   void *_freeres_buf;
290:   size_t __pad5;
291:   int _mode;
292: 
293:   char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
294: };
295: # 44 "/usr/include/stdio.h" 2 3 4
296: # 52 "/usr/include/stdio.h" 3 4
297: typedef __gnuc_va_list va_list;
298: # 63 "/usr/include/stdio.h" 3 4
299: typedef __off_t off_t;
300: # 77 "/usr/include/stdio.h" 3 4
301: typedef __ssize_t ssize_t;
302: 
303: 
304: 
305: 
306: 
307: 
308: typedef __fpos_t fpos_t;
309: # 133 "/usr/include/stdio.h" 3 4
310: # 1 "/usr/include/x86_64-linux-gnu/bits/stdio_lim.h" 1 3 4
311: # 134 "/usr/include/stdio.h" 2 3 4
312: 
313: 
314: 
315: extern FILE *stdin;
316: extern FILE *stdout;
317: extern FILE *stderr;
318: 
319: 
320: 
321: 
322: 
323: 
324: extern int remove (const char *__filename) __attribute__ ((__nothrow__ , __leaf__));
325: 
326: extern int rename (const char *__old, const char *__new) __attribute__ ((__nothrow__ , __leaf__));
327: 
328: 
329: 
330: extern int renameat (int __oldfd, const char *__old, int __newfd,
331:        const char *__new) __attribute__ ((__nothrow__ , __leaf__));
332: # 173 "/usr/include/stdio.h" 3 4
333: extern FILE *tmpfile (void) ;
334: # 187 "/usr/include/stdio.h" 3 4
335: extern char *tmpnam (char *__s) __attribute__ ((__nothrow__ , __leaf__)) ;
336: 
337: 
338: 
339: 
340: extern char *tmpnam_r (char *__s) __attribute__ ((__nothrow__ , __leaf__)) ;
341: # 204 "/usr/include/stdio.h" 3 4
342: extern char *tempnam (const char *__dir, const char *__pfx)
343:      __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__malloc__)) ;
344: 
345: 
346: 
347: 
348: 
349: 
350: 
351: extern int fclose (FILE *__stream);
352: 
353: 
354: 
355: 
356: extern int fflush (FILE *__stream);
357: # 227 "/usr/include/stdio.h" 3 4
358: extern int fflush_unlocked (FILE *__stream);
359: # 246 "/usr/include/stdio.h" 3 4
360: extern FILE *fopen (const char *__restrict __filename,
361:       const char *__restrict __modes) ;
362: 
363: 
364: 
365: 
366: extern FILE *freopen (const char *__restrict __filename,
367:         const char *__restrict __modes,
368:         FILE *__restrict __stream) ;
369: # 279 "/usr/include/stdio.h" 3 4
370: extern FILE *fdopen (int __fd, const char *__modes) __attribute__ ((__nothrow__ , __leaf__)) ;
371: # 292 "/usr/include/stdio.h" 3 4
372: extern FILE *fmemopen (void *__s, size_t __len, const char *__modes)
373:   __attribute__ ((__nothrow__ , __leaf__)) ;
374: 
375: 
376: 
377: 
378: extern FILE *open_memstream (char **__bufloc, size_t *__sizeloc) __attribute__ ((__nothrow__ , __leaf__)) ;
379: 
380: 
381: 
382: 
383: 
384: extern void setbuf (FILE *__restrict __stream, char *__restrict __buf) __attribute__ ((__nothrow__ , __leaf__));
385: 
386: 
387: 
388: extern int setvbuf (FILE *__restrict __stream, char *__restrict __buf,
389:       int __modes, size_t __n) __attribute__ ((__nothrow__ , __leaf__));
390: 
391: 
392: 
393: 
394: extern void setbuffer (FILE *__restrict __stream, char *__restrict __buf,
395:          size_t __size) __attribute__ ((__nothrow__ , __leaf__));
396: 
397: 
398: extern void setlinebuf (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
399: 
400: 
401: 
402: 
403: 
404: 
405: 
406: extern int fprintf (FILE *__restrict __stream,
407:       const char *__restrict __format, ...);
408: 
409: 
410: 
411: 
412: extern int printf (const char *__restrict __format, ...);
413: 
414: extern int sprintf (char *__restrict __s,
415:       const char *__restrict __format, ...) __attribute__ ((__nothrow__));
416: 
417: 
418: 
419: 
420: 
421: extern int vfprintf (FILE *__restrict __s, const char *__restrict __format,
422:        __gnuc_va_list __arg);
423: 
424: 
425: 
426: 
427: extern int vprintf (const char *__restrict __format, __gnuc_va_list __arg);
428: 
429: extern int vsprintf (char *__restrict __s, const char *__restrict __format,
430:        __gnuc_va_list __arg) __attribute__ ((__nothrow__));
431: 
432: 
433: 
434: extern int snprintf (char *__restrict __s, size_t __maxlen,
435:        const char *__restrict __format, ...)
436:      __attribute__ ((__nothrow__)) __attribute__ ((__format__ (__printf__, 3, 4)));
437: 
438: extern int vsnprintf (char *__restrict __s, size_t __maxlen,
439:         const char *__restrict __format, __gnuc_va_list __arg)
440:      __attribute__ ((__nothrow__)) __attribute__ ((__format__ (__printf__, 3, 0)));
441: # 379 "/usr/include/stdio.h" 3 4
442: extern int vdprintf (int __fd, const char *__restrict __fmt,
443:        __gnuc_va_list __arg)
444:      __attribute__ ((__format__ (__printf__, 2, 0)));
445: extern int dprintf (int __fd, const char *__restrict __fmt, ...)
446:      __attribute__ ((__format__ (__printf__, 2, 3)));
447: 
448: 
449: 
450: 
451: 
452: 
453: 
454: extern int fscanf (FILE *__restrict __stream,
455:      const char *__restrict __format, ...) ;
456: 
457: 
458: 
459: 
460: extern int scanf (const char *__restrict __format, ...) ;
461: 
462: extern int sscanf (const char *__restrict __s,
463:      const char *__restrict __format, ...) __attribute__ ((__nothrow__ , __leaf__));
464: 
465: 
466: 
467: 
468: 
469: 
470: extern int fscanf (FILE *__restrict __stream, const char *__restrict __format, ...) __asm__ ("" "__isoc99_fscanf")
471: 
472:                                ;
473: extern int scanf (const char *__restrict __format, ...) __asm__ ("" "__isoc99_scanf")
474:                               ;
475: extern int sscanf (const char *__restrict __s, const char *__restrict __format, ...) __asm__ ("" "__isoc99_sscanf") __attribute__ ((__nothrow__ , __leaf__))
476: 
477:                       ;
478: # 432 "/usr/include/stdio.h" 3 4
479: extern int vfscanf (FILE *__restrict __s, const char *__restrict __format,
480:       __gnuc_va_list __arg)
481:      __attribute__ ((__format__ (__scanf__, 2, 0))) ;
482: 
483: 
484: 
485: 
486: 
487: extern int vscanf (const char *__restrict __format, __gnuc_va_list __arg)
488:      __attribute__ ((__format__ (__scanf__, 1, 0))) ;
489: 
490: 
491: extern int vsscanf (const char *__restrict __s,
492:       const char *__restrict __format, __gnuc_va_list __arg)
493:      __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__format__ (__scanf__, 2, 0)));
494: 
495: 
496: 
497: 
498: extern int vfscanf (FILE *__restrict __s, const char *__restrict __format, __gnuc_va_list __arg) __asm__ ("" "__isoc99_vfscanf")
499: 
500: 
501: 
502:      __attribute__ ((__format__ (__scanf__, 2, 0))) ;
503: extern int vscanf (const char *__restrict __format, __gnuc_va_list __arg) __asm__ ("" "__isoc99_vscanf")
504: 
505:      __attribute__ ((__format__ (__scanf__, 1, 0))) ;
506: extern int vsscanf (const char *__restrict __s, const char *__restrict __format, __gnuc_va_list __arg) __asm__ ("" "__isoc99_vsscanf") __attribute__ ((__nothrow__ , __leaf__))
507: 
508: 
509: 
510:      __attribute__ ((__format__ (__scanf__, 2, 0)));
511: # 485 "/usr/include/stdio.h" 3 4
512: extern int fgetc (FILE *__stream);
513: extern int getc (FILE *__stream);
514: 
515: 
516: 
517: 
518: 
519: extern int getchar (void);
520: 
521: 
522: 
523: 
524: 
525: 
526: extern int getc_unlocked (FILE *__stream);
527: extern int getchar_unlocked (void);
528: # 510 "/usr/include/stdio.h" 3 4
529: extern int fgetc_unlocked (FILE *__stream);
530: # 521 "/usr/include/stdio.h" 3 4
531: extern int fputc (int __c, FILE *__stream);
532: extern int putc (int __c, FILE *__stream);
533: 
534: 
535: 
536: 
537: 
538: extern int putchar (int __c);
539: # 537 "/usr/include/stdio.h" 3 4
540: extern int fputc_unlocked (int __c, FILE *__stream);
541: 
542: 
543: 
544: 
545: 
546: 
547: 
548: extern int putc_unlocked (int __c, FILE *__stream);
549: extern int putchar_unlocked (int __c);
550: 
551: 
552: 
553: 
554: 
555: 
556: extern int getw (FILE *__stream);
557: 
558: 
559: extern int putw (int __w, FILE *__stream);
560: 
561: 
562: 
563: 
564: 
565: 
566: 
567: extern char *fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
568:      ;
569: # 603 "/usr/include/stdio.h" 3 4
570: extern __ssize_t __getdelim (char **__restrict __lineptr,
571:                              size_t *__restrict __n, int __delimiter,
572:                              FILE *__restrict __stream) ;
573: extern __ssize_t getdelim (char **__restrict __lineptr,
574:                            size_t *__restrict __n, int __delimiter,
575:                            FILE *__restrict __stream) ;
576: 
577: 
578: 
579: 
580: 
581: 
582: 
583: extern __ssize_t getline (char **__restrict __lineptr,
584:                           size_t *__restrict __n,
585:                           FILE *__restrict __stream) ;
586: 
587: 
588: 
589: 
590: 
591: 
592: 
593: extern int fputs (const char *__restrict __s, FILE *__restrict __stream);
594: 
595: 
596: 
597: 
598: 
599: extern int puts (const char *__s);
600: 
601: 
602: 
603: 
604: 
605: 
606: extern int ungetc (int __c, FILE *__stream);
607: 
608: 
609: 
610: 
611: 
612: 
613: extern size_t fread (void *__restrict __ptr, size_t __size,
614:        size_t __n, FILE *__restrict __stream) ;
615: 
616: 
617: 
618: 
619: extern size_t fwrite (const void *__restrict __ptr, size_t __size,
620:         size_t __n, FILE *__restrict __s);
621: # 673 "/usr/include/stdio.h" 3 4
622: extern size_t fread_unlocked (void *__restrict __ptr, size_t __size,
623:          size_t __n, FILE *__restrict __stream) ;
624: extern size_t fwrite_unlocked (const void *__restrict __ptr, size_t __size,
625:           size_t __n, FILE *__restrict __stream);
626: 
627: 
628: 
629: 
630: 
631: 
632: 
633: extern int fseek (FILE *__stream, long int __off, int __whence);
634: 
635: 
636: 
637: 
638: extern long int ftell (FILE *__stream) ;
639: 
640: 
641: 
642: 
643: extern void rewind (FILE *__stream);
644: # 707 "/usr/include/stdio.h" 3 4
645: extern int fseeko (FILE *__stream, __off_t __off, int __whence);
646: 
647: 
648: 
649: 
650: extern __off_t ftello (FILE *__stream) ;
651: # 731 "/usr/include/stdio.h" 3 4
652: extern int fgetpos (FILE *__restrict __stream, fpos_t *__restrict __pos);
653: 
654: 
655: 
656: 
657: extern int fsetpos (FILE *__stream, const fpos_t *__pos);
658: # 757 "/usr/include/stdio.h" 3 4
659: extern void clearerr (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
660: 
661: extern int feof (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
662: 
663: extern int ferror (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
664: 
665: 
666: 
667: extern void clearerr_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
668: extern int feof_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
669: extern int ferror_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
670: 
671: 
672: 
673: 
674: 
675: 
676: 
677: extern void perror (const char *__s);
678: 
679: 
680: 
681: 
682: 
683: # 1 "/usr/include/x86_64-linux-gnu/bits/sys_errlist.h" 1 3 4
684: # 26 "/usr/include/x86_64-linux-gnu/bits/sys_errlist.h" 3 4
685: extern int sys_nerr;
686: extern const char *const sys_errlist[];
687: # 782 "/usr/include/stdio.h" 2 3 4
688: 
689: 
690: 
691: 
692: extern int fileno (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
693: 
694: 
695: 
696: 
697: extern int fileno_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
698: # 800 "/usr/include/stdio.h" 3 4
699: extern FILE *popen (const char *__command, const char *__modes) ;
700: 
701: 
702: 
703: 
704: 
705: extern int pclose (FILE *__stream);
706: 
707: 
708: 
709: 
710: 
711: extern char *ctermid (char *__s) __attribute__ ((__nothrow__ , __leaf__));
712: # 840 "/usr/include/stdio.h" 3 4
713: extern void flockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
714: 
715: 
716: 
717: extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
718: 
719: 
720: extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
721: # 858 "/usr/include/stdio.h" 3 4
722: extern int __uflow (FILE *);
723: extern int __overflow (FILE *, int);
724: # 873 "/usr/include/stdio.h" 3 4
725: 
726: # 2 "hello_world.c" 2
727: 
728: # 2 "hello_world.c"
729: int main(){
730:   printf("Hello, World!\n");
731: }

Wow! That's a lot! What happened is that the entirety of the stdio.h header was pasted into hello_world.c which includes a forward declaration of printf that satisfies gcc enough not to give a warning.

Contact: [email protected] | rss feed | Compiled with org-mode | Licensed under CC BY-NC-SA 4.0