extern function during linkage - c

My question is a continuation of this one:
extern function during linkage?
I now tried in file2.c:
extern int foo(void);
and I called
foo(1,2,3);
Now, I got a compilation error that there are too many arguments in
foo(1,2,3);
Why does that happen ? We just said that extern functions are looked for during linkage and that in that stage there's no consideration regarding the parameters...

extern functions are looked for during linkage and that in that stage there's no consideration regarding the parameters.
That's exactly right. However, you get an error at the compiling stage, not at linkage stage. You promised the compiler that there is a function foo that takes no parameters, and then you call foo with three parameters. Compiler does not take that, and reports the error.
The problem with the linker disregarding parameters would be if you separately compiled foo with zero parameters and a call to foo with a non-matching prototype that takes three parameters. This is undefined behavior.
impl.c
void foo() {}
main.c
void foo(int,int,int);
int main(int argc, char *argv[]) {
foo(1, 2, 3);
return 0;
}
If you compile the above, it would link, because you tricked the compiler by giving it a wrong prototype, and the linker does not know any better.

by saying extern int foo(void);, you're telling the compiler to look for the function definition at linking time. In this process, you're already supplying the function prototype [declaration] int foo(void);, where the number of parameter is 0.
But, while using , you're calling foo(1,2,3);, so the comilation error is happenning.
Note: If i'm not mistaken, function declarations are by default extern.

Related

why no need to add `extern` for external functions?

below is my code:
//main.c
//I'm not using header file here,I know it is bad practice, it is just for demo purpose.
int main()
{
func();
return 0;
}
//test.c
void func()
{
...
}
we can see that above code compiles and can be linked by linker, but the same thing doesn't apply to variables as:
//main.c
int main()
{
sum += 1;
return 0;
}
//test.c
int sum = 2020;
then this code won't compile and can't be linked, and we have to add extern int sum; before main function in main.c.
But why we don't need to add extern in main.c as:
//main.c
extern void func(); //or `void func();` since functions are by default external
// without above line, it still compile
int main()
{
func();
return 0;
}
is it a little bit inconsistent here?
Note: by saying " Functions are by default external.",my understanding is: we can save some keystokes without typing extern , so void func(); == extern void func();, but we still need to add void func(); before main function in main.c, isn't it?
Both programs are incorrect since C99 and may be rejected by the compiler. An identifier may not be used in an expression without previously being declared.
In C89 there was a rule that if you write something that resembles a function call, and the function name has not previously been declared, then the compiler inserts a function declaration int f(); . There was not a similar rule for use of other identifiers that aren't followed by parentheses.
Some compilers (depending on compiler flags) will, even if set to C99 or later mode, issue a diagnostic and then perform the C89 behaviour anyway.
Note: your program still causes undefined behaviour in C89 because the implicit declaration is int func(); but the function definition has void func() which is incompatible type.
The compiler doesn't need to know anything about a function, in order to generate code to call it. In the absence of a prototype, it might generate the wrong code, but it can generate something (in principle, at least -- standards-compliance might forbid it by default). The compiler knows the calling convention for the platform -- it knows to put the function arguments onto the stack or into registers as required. It knows to write a symbol that the linker can later find and fix up, and so on.
But when you write "sum++", the compiler has no clue, lacking a declaration, how to generate code for that. It doesn't even know what kind of thing "sum" is. The code needed to increment a floating-point number will be completely different to that needed to increment an integer, and may be different from that needed to increment a pointer. The compiler doesn't need to know where "sum" is -- that's the linker's job -- but it needs to know what it is, to produce meaningful machine code.
But we don't need to add extern for the function in main.c as extern void func(); or void func();(as functions are implicitly extern prefixed) and the code still compile?
That's correct. Functions are by default external.
To make functions specific to a local source file (translation unit), you need to specific static for them.
Variables, on the other hand, are visible in the source file only. If you want to make some variable visible outside the source file where it is defined, you need extern for it.
There are two completely different topics - function prototypes and linkage.
void foo(void);
provides the extern function prototype needed by compiler to know the number and type of parameters and the type of the return value. Function has an external linkage - ie can be accessed by other compilation units
static void foo(void);
provides the static function prototype. Function has an no external linkage - ie it cannot be accessed by other compilation units
By default functions have an external linkage.
Objects (global scope).
int x;
Defines the object x having the external linkage and type int.
If you define another x object in another compilation unit the linker will complain and emit an error.
extern int x;
Only declares the object x without defining it. The object x has to be defined in other compilation unit.

extern function during linkage?

I have this weird thing:
in a file1.c there's
extern void foo(int x, int y);
..
..
int tmp = foo(1,2);
in the project I could find only 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 isn't included in file1.c (this is why who wrote it used extern, i guess).
this project compiles fine, I think that's because in file1.c foo() will be looked for only during linkage, am I right?
but my real question is : why is the linkage succssful ?
after all, there is no such function as foo with 2 parameters....
and i'm in c .. so there's no overloading..
so what's going on ?
Because there is no overloading, the C compiler does not decorate the function names. The linker finds in file2.c a reference to function foo and in file1.c it finds a function foo. It cannot know their parameter lists do not match and happily use them.
Of course, when the function foo runs the value of z is garbage and the behavior of the program becomes unpredictable from that point on.
Calling a function with the wrong number (or types) of arguments is an error.
The standard requires the implementation to detect some, but not all of them.
What the standard calls an implementation, is typically a compiler with a separate linker (and some other things), where a compiler translates single translation units (that is, a preprocessed source file) into object files, which later get linked together.
While the standard doesn't distinct between them, its authors of course wrote it with the typical setup in mind.
C11 (n1570) 6.5.2.2 "Function calls", p2:
If the expression that denotes the called function has a type that includes a prototype, the number of arguments shall agree with the number of parameters. Each argument shall have a type such that its value may be assigned to an object with the unqualified version of the type of its corresponding parameter.
This is in a "constraints" section, which means, the implementation (in this case, that's the compiler) must complain and may abort translation if a "shall" requirement is violated.
In your case, there was a prototype visible, so the arguments of the function call must match with the prototype.
Similar requirements apply for a function definition with a prototype declaration in scope; if your function definition doesn't match the prototype, your compiler must tell you. In other words, as long as you ensure that all calls to a function and that function's definition are in the scope of the same prototype, you are told if there is a mismatch. This can be ensured if the prototype is in a header file which is included by all files with calls to that function and by the file containing its definition. We use header files with prototypes exactly for that reason.
In the code shown, this checking is by-passed by providing a non-matching prototype and not including the header file2.h.
Ibid. p9:
If the function is defined with a type that is not compatible with the type (of the expression) pointed to by the expression that denotes the called function, the behavior is undefined.
Undefined behaviour means, the compiler is free to assume it doesn't happen, and is not required to detect if it does.
And in fact, on my machine, the generated object files from file2.c (I inserted a return 0; to have some function body), don't differ if I remove one of the function arguments, which means, the object file doesn't contain any information about the arguments und thus a compiler seeing only file2.o and file1.c hasn't got any chance to detect the violation.
You've mentioned overloading, so let's compile 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
Function foo has its arguments incorporated into the symbol created for it (a process called name mangling), the object file indeed carries some information about the function types. Accordingly, we get an error at link time:
$ 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 behaviour would also be allowed for a C implementation, aborting translation is a valid manifestation of undefined behaviour at compile or link time.
The way overloading in C++ is usually done actually allows such checks at link time. That C doesn't have built-in support for function overloading, and that the behaviour is undefined for the cases where the compiler cannot see the type mismatches, allows to generate symbols for functions without any type information.
First of all
extern void foo(int x, int y);
means exactly the same thing as
void foo(int x, int y);
The former is just an overly explicit way to write the same thing. extern fills no other purpose here. It is like writing auto int x; instead of int x, it means the very same thing.
In your case, the "foo" module (which you call file2) contains the function prototype as well as the definition. This is proper program design in C. What file1.c should be doing is to #include the foo.h.
For reasons unknown, whoever wrote file1.c didn't do this. Instead they are just saying "elsewhere in the project, there is this function, do not care about its definition, that's handled elsewhere".
This is bad programming practice. file1.c shouldn't concern itself with how things are defined elsewhere: this is spaghetti programming which creates a needless tight coupling between the caller and the module. There is also the chance that the actual function doesn't match the local prototype, in which case you would hopefully get linker errors. But there are no guarantees.
The code must be fixed like this:
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)
{
....
}

extern with global definition of variable in c

I have the following source code which interests me.
#include <stdio.h>
extern int foo;
int foo = 32;
int main()
{
printf("%d", foo);
}
This a perfectly normal piece of code, and when I compile it with
gcc -Wall -Wextra -pedantic foo.c
I get no warnings.
And it seems weird, because a variable is defined both as external, and also global in the same file.
I'm quite sure that it's easy to the linker to find the reference for the external variable in the same file, but doesn't it look like a coding error? And if so, why doesn't the compiler warn about this?
There's nothing weird. You first made a declaration of a variable (you promised the compiler that it exist) and then you actually defined it. There's no problem in that.
Also, by default, all variables that aren't local to functions and aren't defined as static are extern.
You seem to misunderstand what extern does. extern simply makes your declaration just a declaration instead of a definition.
int i; //definition of i
extern int i; //declaration of i
It is perfectly normal to have multiple declarations of the same variable, but only one definition should be present in the whole program. Compare this with a function
void f(void); //declaration
void f(void) //definition(and redeclaration)
{
} //definition
In order to use a variable or function, you only need its declaration. Its definition may appear anywhere in the program (the linker will find it). Anywhere can be the same file, another file, or even an external library.
And it's seems weired, because a variable is defined both as external, and also global in the same file.
extern int foo;
says: it declares without defining an object of type int named foo.
int foo = 32;
it declares and defines an object of type int named foo with external linkage.
There is no contradiction and it is valid C code.
The difference is that the former is a declaration -> extern declares a variable and says it will be available somewhere around. You can have as many declarations as you want and the latter is a definition which must be there exactly once.
So there should be no warning and no error.
extern is a way to provide visibility to a variable that is defined elsewhere...
extern is like a promise...
in example.h
extern int g;// promises that this will be in the object code to anything that includes example.h
example. c
int g;

extern declaration and function definition both in the same file

I was just browsing through gcc source files. In gcc.c, I found something like
extern int main (int, char **);
int
main (int argc, char **argv)
{
Now my doubt is extern is to tell the compiler that the particular function is not in this file but will be found somewhere else in the project. But here, definition of main is immediately after the extern declaration. What purpose is the extern declaration serving then?
It seems like, in this specific example, extern seems to be behaving like export that we use in assembly, wherin we export a particular symbol outside of the module
Any ideas?
You are misunderstanding the extern - it does not tell the compiler the definition is in another file, it simply declares that it exists without defining it. It's perfectly okay for it to be defined in the same file.
C has the concept of declaration (declaring that something exists without defining it) and definition (actually bringing it into existence). You can declare something as often as you want but can only define it once.
Because functions have external linkage by default, the extern keyword is irrelevant in this case.
Functions are implicitly extern in C. Including extern is just a visual reminder. Side note, to make a function not extern you can use the static keyword.
In a function declaration, extern simply declares that the function has external linkage, which is the default; the extern keyword is utterly useless in this context, and the effect is identical to a normal declaration/prototype without the extern keyword.
The warnings likely suggested a function prototype was missing. That's all.
The definition of the main function:
int main(int argc, char **argv) { ... }
is already a declaration is the prototyped syntax of the function main with external linkage. This means a prototyped declaration with extern just before the main definition is redundant.

Warning/error "function declaration isn't a prototype"

I have a library I created,
File mylib.c:
#include <mylib.h>
int
testlib() {
printf("Hello, World!\n");
return (0);
}
File mylib.h:
#include <stdio.h>
extern int testlib();
In my program, I've attempted to call this library function:
File myprogram.c:
#include <mylib.h>
int
main (int argc, char *argv[]) {
testlib();
return (0);
}
When I attempt to compile this program I get the following error:
In file included from myprogram.c:1
mylib.h:2 warning: function declaration isn't a prototype
I'm using: gcc (GCC) 3.4.5 20051201 (Red Hat 3.4.5-2)
What is the proper way to declare a function prototype?
In C int foo() and int foo(void) are different functions. int foo() accepts an arbitrary number of arguments, while int foo(void) accepts 0 arguments. In C++ they mean the same thing. I suggest that you use void consistently when you mean no arguments.
If you have a variable a, extern int a; is a way to tell the compiler that a is a symbol that might be present in a different translation unit (C compiler speak for source file), don't resolve it until link time. On the other hand, symbols which are function names are anyway resolved at link time. The meaning of a storage class specifier on a function (extern, static) only affects its visibility and extern is the default, so extern is actually unnecessary.
I suggest removing the extern, it is extraneous and is usually omitted.
Quick answer: change int testlib() to int testlib(void) to specify that the function takes no arguments.
A prototype is by definition a function declaration that specifies the type(s) of the function's argument(s).
A non-prototype function declaration like
int foo();
is an old-style declaration that does not specify the number or types of arguments. (Prior to the 1989 ANSI C standard, this was the only kind of function declaration available in the language.) You can call such a function with any arbitrary number of arguments, and the compiler isn't required to complain -- but if the call is inconsistent with the definition, your program has undefined behavior.
For a function that takes one or more arguments, you can specify the type of each argument in the declaration:
int bar(int x, double y);
Functions with no arguments are a special case. Logically, empty parentheses would have been a good way to specify that a function takes no arguments, but that syntax was already in use for old-style function declarations, so the ANSI C committee invented a new syntax using the void keyword:
int foo(void); /* foo takes no arguments */
A function definition (which includes code for what the function actually does) also provides a declaration. In your case, you have something similar to:
int testlib()
{
/* code that implements testlib */
}
This provides a non-prototype declaration for testlib. As a definition, this tells the compiler that testlib has no parameters, but as a declaration, it only tells the compiler that testlib takes some unspecified but fixed number and type(s) of arguments.
If you change () to (void) the declaration becomes a prototype.
The advantage of a prototype is that if you accidentally call testlib with one or more arguments, the compiler will diagnose the error.
(C++ has slightly different rules. C++ doesn't have old-style function declarations, and empty parentheses specifically mean that a function takes no arguments. C++ supports the (void) syntax for consistency with C. But unless you specifically need your code to compile both as C and as C++, you should probably use the () in C++ and the (void) syntax in C.)
Try:
extern int testlib(void);

Resources