External function during grip?

I have this weird thing:

in file1.c is

extern void foo(int x, int y); .. .. int tmp = foo(1,2); 

in the project, I could only find this foo ():

in file2.c:

 int foo(int x, int y, int z) { .... } 

in file2.h:

 int foo(int x, int y, int z); 

file2.h is not included in file1.c (that's why who wrote it, used extern, I think).

This project compiles fine, I think that since in file1.c foo () will only search during binding, am I right?

but my real question is: why is the connection succssful? after all, there is no function like foo with two parameters .... and I'm in c .. so there is no overload ..

So what is going on?

+5
source share
3 answers

Since there is no overload, the C compiler does not decorate function names. The linker finds a link to the foo function in file2.c , and finds the foo function in file1.c . He cannot know that their parameter lists do not match and are happy to use them.

Of course, when the function foo runs the value z , it is garbage, and the behavior of the program becomes unpredictable from this point.

+7
source

Calling a function with the wrong number (or types) of arguments is an error. The standard requires that an implementation detect some, but not all, of them.

That the standard calls the implementation is usually a compiler with a separate linker (and some other things), where the compiler translates the single translation units (i.e. the preprocessed source file) into object files that are later combined together, although the standard is not different, its authors, of course, wrote it with a typical setting.

C11 (n1570) 6.5.2.2 "Functional Calls", p2:

If the expression denoting the called function is of a type that includes the prototype, the number of arguments must match the number of parameters. Each argument must be of a type so that its value can be assigned to an object with an unqualified version of the type of its corresponding parameter.

This is in the โ€œrestrictionsโ€ section, which means that the implementation (in this case, the compiler) must complain and can interrupt the translation if the โ€œrequiredโ€ requirement is violated.

In your case, the prototype was visible, so the arguments to the function call must match the prototype.

Similar requirements apply to defining a function with a prototype declaration in an area; if your function definition does not match the prototype, your compiler should tell you. In other words, until you make sure that all function calls and the definition of this function are within the same prototype, you are informed if there is a mismatch. This can be achieved if the prototype is in the header file, which is included with all files with calls to this function and a file containing its definition. For this reason, we use prototype header files.

In the code shown, this check circumvents by providing a mismatch prototype and does not include the file2.h header.

In the same place. P9:

If a function is defined with a type that is incompatible with the type (of the expression) that the expression that indicates the function to call points to, the behavior is undefined.

Undefined behavior means that the compiler can assume that this is not happening and is not required to detect what it is doing.

And actually on my machine the generated object files from file2.c (I inserted return 0; to have some function body), it does not differ if I delete one of the function arguments, which means that the object file does not contain any information about arguments, and therefore the compiler only sees file2.o and file1.c . chance to detect a violation.

You mentioned overloading, so give compilation file2.c (with two and three arguments) as C ++ and look at the object files:

 $ g++ file2_three_args.cpp -c $ g++ file2_two_args.cpp -c $ nm file2_three_args.o 00000000 T _Z3fooiii $ nm file2_two_args.o 00000000 T _Z3fooii 

The foo function has its arguments included in the symbol created for it (a process called name change), the object file does contain some information about the types of functions. Accordingly, we get an error during the connection:

 $ cat file1.cpp extern void foo(int x, int y); int main(void) { foo(1,2); } $ g++ file2_three_args.o file1.cpp In function `main': file1.cpp:(.text+0x19): undefined reference to `foo(int, int)' collect2: error: ld returned 1 exit status 

This behavior will also be allowed to implement C, and interruption of the translation is a valid manifestation of undefined behavior at compile time or link time.

The way overloading in C ++ is usually done actually allows such checks during connection. This C does not have built-in support for function overloading and that undefined behavior for cases when the compiler cannot see type mismatches allows the generation of characters for functions without type information.

+1
source

Primarily

 extern void foo(int x, int y); 

means the same as

 void foo(int x, int y); 

The first is just an explicit way to write the same thing. extern is not used here. This is similar to writing auto int x; instead of int x , it means the same thing.


In your case, the module "foo" (which you call file2) contains the function prototype as well as the definition. This is the correct program in C. The file1.c should have #include foo.h.

For unknown reasons, whoever wrote the file1.c file did not. Instead, they simply say "in another place in the project, there is this function, they donโ€™t care about its definition, which is processed elsewhere."

This is bad programming practice. file1.c does not have to care about how things are defined elsewhere: it is spaghetti programming that creates an unnecessary hard link between the caller and the module. There is also the possibility that the actual function does not match the local prototype, in which case you hopefully get linker errors. But there are no guarantees.

The code should be fixed as follows:

file1.c

 #include "foo.h" ... int tmp = foo(1,2); 

foo.h

 #ifndef FOO_H #define FOO_H int foo(int x, int y, int z); #endif 

foo.c

 #include "foo.h" int foo(int x, int y, int z) { .... } 
0
source

Source: https://habr.com/ru/post/1207719/


All Articles