Consider the following sources: main.c
int main(){
print_hello("str");
return 0;
}
and hello.c
#include<stdio.h>
void print_hello(){
printf("Hello world\n");
}
After compiling and linking gcc -o hello hello.c main.c
it's work fine, but I'm expected that error will be occured. Because signatures of print_hello
in main.c
and print_hello
in hello.c
are differents. Why it works fine?
You've not told the compiler about what the print_hello()
function looks like in the file main.c
. If you had a header file hello.h
such as:
#ifndef HELLO_H_INCLUDED
#define HELLO_H_INCLUDED
extern void print_hello(void);
#endif
And you had #include "hello.h"
at the top of each file, then you'd get the relevant compiler warnings from misusing print_hello()
in main.c
.
Your compiler uses calling convention which allows extra arguments passing to called function without extra effects. This is typical between calling conventions for C, due to its support of variable argument lists (as in printf, scanf, etc.) In such conventions,
In X86 calling conventions this is usually named "cdecl" (optionally, with 1 or 2 underscores).
A such convention is tolerable to extra arguments, but, definitely, not to unspecified arguments which are then used by a callee function; the latter case results in garbage in arguments.
Generally one shouldn't exploit such runtime features, but there are some corner cases it's useful.
To prevent mismatch between a function use and its definition, you should use identical declarations for both. Typically it's done including the same header file to all sources where this function is declared or called.
In addition to the other explanations, assuming GCC 4.8 or better on Linux :
You should compile with gcc -Wall -std=c99
to get all warnings ( -Wall
) and to tell the compiler which standard you want to obey ( -std=c99
). With these settings you get warned:
main.c: In function 'main':
main.c:2:5: warning: implicit declaration of function 'print_hello'
[-Wimplicit-function-declaration]
print_hello("str");
^
As to why no errors are given, they could be given only at link time by the linker ( ld
, called by gcc
). And Unix and Linux linkers (from GNU binutils ) work only with names: each function (and more generally each linked symbol) has a name (and both object files and executables are in ELF , which defines how names are represented, etc....) If two names are the same the linker resolves by making them refer to the same address (see Linkers and Loaders by Levine). So since both names (or symbols) in main.o
and hello.o
are print_hello
they are linked together. Use nm
to query the names in an ELF object or executable file. Of course, what happens then at runtime is undefined behavior , but the ABI conventions for x86 (and x86-64 ) enable the behavior you expect. The important thing is that ELF do not keep typing or signature meta-data in object files.
With C++, it is a bit different: the compiler is transforming a function name by name mangling (so names in ELF *.o
files are not simply the C++ source name), so the linker sees different names (and would have failed).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.