below given program is working without including <stdio.h>? Why does this work?
int main()
{
printf("integra");
return 0;
}
Definition of printf() is there in libc.so and the dynamic linker will take care of it even if you don't include the header file. During compile time, printf() will be an undefined symbol and it assumes that it may find the definition later on in libc. The header file will just give the proto-type and suppress the compiler(warnings) stating that the definition of the prototype is present in glibc. So basically, the header files are included just to make sure that the definitions are available in our libraries, to help the developer.
in older standard, undeclared function assume int argument and return value. Your char* have same size (32-bit) as int, so everything work.
Just don't do it.
printf() is only defined in libc.so
The dynamic linker will resolve the symbol printf() in libc since you have not included it
libc is default in gcc for every program
As Abi pointed out, your code builds successfully without including stdio.h because the linker is defaulting to the system std library for the undefined symbol (printf). GCC would normally warn you of such cases.
Let test.c be:
1: int main()
2: {
3: printf("test\n");
4: return 0;
5: }
Building test.c with GCC 4.2.1 on Mac OSX:
$ gcc test.c
test.c: In function ‘main’:
test.c:3: warning: incompatible implicit declaration of built-in function ‘printf’
$ ./a.out
test
You can disable this default linking by specifying a GCC linker option -nostdlib (or -nodefaultlibs) along with -lgcc (as the GCC manual recommends):
$ gcc -nostdlib -lgcc test.c
test.c: In function ‘main’:
test.c:3: warning: incompatible implicit declaration of built-in function ‘printf’
Undefined symbols:
"_puts", referenced from:
_main in cc3bvzuM.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
$
Some (old?) compilers do not require prototypes before calling functions.
When you use a function that has not been declared, then the compiler will assume this function returns an int and takes an unspecified, but fixed, number of arguments.
If this assumption matches with the definition of the function, and if the arguments you provided also match (modulo the default argument promotions) the parameters that the function expects to receive, then everything is well.
If the assumption is incorrect (like for printf, which is a variadic function), or when the arguments don't match, the results are undefined. One of the nasty things of undefined behaviour is that it can appear to work as expected.
Related
I have the following code:
int main()
{
printf("Hello\n");
return 0;
}
I compiled it using the following command:
gcc -o myprogram myfile.c
And it compiled without any error even though I did not #include <stdio.h>. So did gcc include this header file automatically?
My gcc version is 4.3.3
In ANSI C, you can call functions you didn't declare. Such functions are implicitly declared the first time you call them. They are assumed to return int and take arguments according to the default argument promotions. Since you didn't include <stdio.h>, the compiler uses this rule and implicitly declares printf. Note that this is undefined behaviour as functions that take variable argument lists like printf must be declared explicitly. gcc usually warns you if it uses the implicit declaration rule since it's usually not intentionally used.
No, gcc did not include any header files you didn't request. #include statements are C preprocessor macros (like #define or #if) that are actually evaluated before the actual C compilation. You can see what your code looks like after all macros are resolved by calling gcc -E myfile.c. As you will see, printf will still not be declared.
If you compile with -Wall, you should get a warning that printf is undeclared. However gcc "guesses" how printf is used (probably from its arguments, but it could also simply know the routine internally). Since it finds a matching symbol name while linking, you don't get an error and your program runs just fine.
BTW, gcc 5.3.0 shows the following warning:
myfile.c: In function 'main':
myfile.c:3:5: warning: implicit declaration of function 'printf' [-Wimplicit-function-declaration]
printf("Hello\n");
^
myfile.c:3:5: warning: incompatible implicit declaration of built-in function 'printf'
myfile.c:3:5: note: include '<stdio.h>' or provide a declaration of 'printf'
I have simple program without includes that compiles with some warnings:
int main(int argc, char **argv)
{
printf("hello");
exit(0);
}
Compile:
gcc hello.c
Warning:
In function ‘main’:
warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
printf("hello");
^
warning: incompatible implicit declaration of built-in function ‘exit’ [enabled by default]
exit( 0 );
^
compilation command is very simple and not contains information regarding include library files that contains printf and exit. Correct me if I'm wrong, but looks that gcc links my project to these libraries by default. That points me to thinking that include files of libc libraries is not required?
Correct me once again. I got warnings because GCC somehow knows some basic functions of libc and these functions has different params. But since GCC checks all libc it founds correct function anyway.
What is libc at all. Is it some standard set of binary object and header files?
looks that gcc links my project to these libraries by default. That points me to thinking that include files of libc libraries is not required?
Includes and linking are not related that way. The includes contain function prototypes that instruct the compiler about the return value type and parameters of a given function. When a function call happens, and there is no prototype for it yet the compiler assumes it returns int and that may lead to undefined behavior.
The program will be linked to the standard libraries and function definitions will be available, but since the program was compiled with the assumption that these functions all return int there can be runtime errors related to this, which cannot be predicted since the behavior is undefined.
I got warnings because GCC somehow knows some basic functions of libc and these functions has different params. But since GCC checks all libc it founds correct function anyway.
No, it has nothing to do with gcc knowing anything but the opposite, it has to do with gcc not knowing how to call these functions.
What is libc at all. Is it some standard set of binary object and header files?
libc is a binary file libc.so.6 in current glibc and it's the runtime library with all the symbols needed by a standard c program, it does not include math.h funcions for example (that is libm.so.6).
You still need header files in your c programs for the reasons explained above, or at least declarations of the standard functions you use. These declaration are called prototypes and are required by the compiler in order to correctly compile your code.
NOTE: Always compile with at least -Wall -Werror, like this
gcc -Wall -Werror hello.c
I have simple application:
#include <stdio.h>
int main( int argc, char ** argv )
{
printf( "hello");
exit( 0 );
}
When I compile it with command
gcc -c count_words.c
I have warning:
warning: incompatible implicit declaration of built-in function ‘exit’ [enabled by default]
exit( 0 );
I was trying to find where exit() function is defined. And found that it is defined in stdlib.h. But it is not included in my project and no additional libs defined in compile command.
Correct me if I'm wrong, but looks like gcc takes some libs as default. What are these libs and is it possible to tell gcc not include them?
Why compiler is not happy regarding exit(0) assuming that it somehow includes stdlib.h as default?
Let's take your example:
#include <stdio.h>
int main( int argc, char ** argv )
{
printf("hello\n");
exit(56);
}
Although we get a warning on compilation:
~$ gcc test.c -o test
test.c: In function ‘main’:
test.c:6:5: warning: implicit declaration of function ‘exit’ [-Wimplicit-function-declaration]
exit(56);
^
test.c:6:5: warning: incompatible implicit declaration of built-in function ‘exit’
test.c:6:5: note: include ‘<stdlib.h>’ or provide a declaration of ‘exit’
Anyway, I think you have tried to run it and make sure it works:
~$ ./test
hello
~$ echo $?
56
#Mat was right when he said that:
You're mixing up including headers and linking to libraries. Those are
two completely different things
The C compiler and linker are totally separate tools. Let's look on this. Actually, this program depends on the standard C library (as all programs if you didn't pass -nostdlib to compiler) and a couple of system libraries (like loader and vdso). You may see it with:
~$ ldd test
linux-vdso.so.1 (0x00007fff1b128000)
libc.so.6 => /lib64/libc.so.6 (0x00007f804389f000)
/lib64/ld-linux-x86-64.so.2 (0x0000557744537000)
These three library is a minimal set for any program. The exit function is defined in the standard library or libc.so.6 in our case. Now let's look on the compilation process in verbose mode. You can achieve this by the passing -v or --verbose option to compiler:
gcc test.c -o test --verbose
If you will execute this, you will find lines like these:
#include <...> search starts here:
/usr/lib/gcc/x86_64-redhat-linux/5.3.1/include
/usr/local/include
/usr/include
So, compile knows where to search header files for stdlib and it starts to search it to find declaration for non-local functions. Note that it searches only in header files which are included in your source code file. It can find printf declaration in thestdio.h, but can't locate declaration of the exit.
After this step, the compile starts to link your program with libraries:
/usr/libexec/gcc/x86_64-redhat-linux/5.3.1/collect2 ... -lc ...
Where collect2 is gcc util which tries to link your program with lc which is standard C library. Note that the process consists from two steps: compilation and linking. That's why your program works.
Additionally, gcc supports -M option which will tell you about dependencies of the main file. So, if you will execute it, you will see the set of header files including stdio.h, but not stdlib.h:
$ gcc -M test.c
test.o: test.c /usr/include/stdc-predef.h /usr/include/stdio.h \
/usr/include/features.h /usr/include/sys/cdefs.h \
/usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \
/usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
Or even better, try to pass -E option to gcc:
$ gcc -E test.c
and you will see result right after the first stage - preprocessing stage. I think it is the easiest way to understand why you are getting this warning.
assuming that it somehow includes stdlib.h as default?
It simply doesn't. That wouldn't be standards-compliant.
So, when you use exit, it has never been declared, so there's you implicit declaration upon usage. However, the fact to you implement exit nowhere else will only become a problem at the final linkage.
Now, GCC knows damn well that you are about to get into trouble, so it warns you.
Simply actually include stdlib.h and you should be fine.
The "library" in question is gcc/builtins.def from the gcc source tree.
That's not just a header file though, and it does not provide declarations for you to use. But it has proper prototypes to check yours against.
Calling undeclared exit() results in implicit declaration like this:
int exit(int);
Search "c implicit declarations" for the gory details. In this case however GCC has its own prototype for exit() from builtins.def:
void exit(int) __attribute__((nothrow,noreturn));
These declarations do not match, and that's what you are being warned about.
Your code works with warning not with error. If you add
#include <stdlib.h>
then no warning anymore ;)
I have just started to learn C as a hobby. I am doing it with the "C programming: A Modern Approach" book. There is a first program there which is called pun.c. Here is the code:
#include <stdio.h>
int main(void)
{
int int_figure;
float float_figure;
int_figure = 12;
float_figure = 12.0;
printf("To C or not to C, this is a question\n");
printf("%d\n", int_figure);
printf("%.2f\n", float_figure);
return 0;
}
Actually it does not matter because the thing I want to ask about is the same with any .c file compilation with gcc.
So in the book there are some options for gcc which allow finding errors during compilation.One of them is -Wall, another one is -pedantic. So when I compile the file with this option, the output in terminal is the following:
nickdudaev|c $ gcc -o -Wall pun pun.c
pun: In function `_fini':
(.fini+0x0): multiple definition of `_fini'
/usr/lib/gcc/x86_64-unknown-linux-gnu/5.1.0/../../../../lib/crti.o:(.fini+0x0): first defined here
pun: In function `data_start':
(.data+0x0): multiple definition of `__data_start'
/usr/lib/gcc/x86_64-unknown-linux-gnu/5.1.0/../../../../lib/crt1.o:(.data+0x0): first defined here
pun: In function `data_start':
(.data+0x8): multiple definition of `__dso_handle'
/usr/lib/gcc/x86_64-unknown-linux-gnu/5.1.0/crtbegin.o:(.data+0x0): first defined here
pun:(.rodata+0x0): multiple definition of `_IO_stdin_used'
/usr/lib/gcc/x86_64-unknown-linux-gnu/5.1.0/../../../../lib/crt1.o:(.rodata.cst4+0x0): first defined here
pun: In function `_start':
(.text+0x0): multiple definition of `_start'
/usr/lib/gcc/x86_64-unknown-linux-gnu/5.1.0/../../../../lib/crt1.o:(.text+0x0): first defined here
pun: In function `_init':
(.init+0x0): multiple definition of `_init'
/usr/lib/gcc/x86_64-unknown-linux-gnu/5.1.0/../../../../lib/crti.o:(.init+0x0): first defined here
/tmp/cc2TRR93.o: In function `main':
pun.c:(.text+0x0): multiple definition of `main'
pun:(.text+0xf6): first defined here
/usr/lib/gcc/x86_64-unknown-linux-gnu/5.1.0/crtend.o:(.tm_clone_table+0x0): multiple definition of `__TMC_END__'
pun:(.data+0x10): first defined here
/usr/bin/ld: error in pun(.eh_frame); no .eh_frame_hdr table will be created.
collect2: error: ld returned 1 exit status
The program although runs correctly.
nickdudaev|c $ ./pun
To C or not to C, this is a question
12
12.00
So to the questions.
Should I on this stage (of learning) worry about this output and at all use those options?
Do I have probably some systematic error? Because output is the same for any file compilation. Maybe something is not properly installed?
I tried to search Google, but the only thing I found is descriptions of what gcc options do. But nothing about possible output and what to do with it.
This:
gcc -o -Wall pun pun.c
doesn't look right. You're saying -Wall where you should say the name of the output, i.e. the argument to -o.
Try:
gcc -Wall -o pun pun.c
Basically you're feeding pun, the old binary, to gcc as a source file.
The -o option in gcc is used to specify a custom output file name, otherwise,
If -o is not specified, the default is to put an executable file in a.out.
The recommended format is -o file. The next expected argument after -o is a filename, not another switch. See the online manual for more details.
You should re-write your compilation statement as
gcc -o pun pun.c -Wall
I'm getting a number of these warnings when compiling a few binaries:
warning: incompatible implicit declaration of built-in function ‘strcpy’
warning: incompatible implicit declaration of built-in function ‘strlen’
warning: incompatible implicit declaration of built-in function ‘exit’
To try to resolve this, I have added
#include <stdlib.h>
at the top of the C files associated with this warning, in addition to compiling with the following flags:
CFLAGS = -fno-builtin-exit -fno-builtin-strcat -fno-builtin-strncat -fno-builtin-strcpy -fno-builtin-strlen -fno-builtin-calloc
I am using GCC 4.1.2:
$ gcc --version
gcc (GCC) 4.1.2 20080704
What should I do to resolve these warnings?
In C, using a previously undeclared function constitutes an implicit declaration of the function. In an implicit declaration, the return type is int if I recall correctly. Now, GCC has built-in definitions for some standard functions. If an implicit declaration does not match the built-in definition, you get this warning.
To fix the problem, you have to declare the functions before using them; normally you do this by including the appropriate header. I recommend not to use the -fno-builtin-* flags if possible.
Instead of stdlib.h, you should try:
#include <string.h>
That's where strcpy and strncpy are defined, at least according to the strcpy(2) man page.
The exit function is defined in stdlib.h, though, so I don't know what's going on there.
In the case of some programs, these errors are normal and should not be fixed.
I get these error messages when compiling the program phrap (for example). This program happens to contain code that modifies or replaces some built in functions, and when I include the appropriate header files to fix the warnings, GCC instead generates a bunch of errors. So fixing the warnings effectively breaks the build.
If you got the source as part of a distribution that should compile normally, the errors might be normal. Consult the documentation to be sure.
Here is some C code that produces the above mentioned error:
int main(int argc, char **argv) {
exit(1);
}
Compiled like this on Fedora 17 Linux 64 bit with gcc:
el#defiant ~/foo2 $ gcc -o n n2.c
n2.c: In function ‘main’:
n2.c:2:3: warning: incompatible implicit declaration of built-in
function ‘exit’ [enabled by default]
el#defiant ~/foo2 $ ./n
el#defiant ~/foo2 $
To make the warning go away, add this declaration to the top of the file:
#include <stdlib.h>
I met these warnings on mempcpy function. Man page says this function is a GNU extension and synopsis shows:
#define _GNU_SOURCE
#include <string.h>
When #define is added to my source before the #include, declarations for the GNU extensions are made visible and warnings disappear.