I have used extern for creating an array but seems it's giving me an error
"undefined reference to `callback_Task'"
// test.h
typedef struct {
uint32_t count;
uint32_t total;
} callback_task;
extern volatile callback_task callback[10];
Now in C source file
// test.c
void test_task(void) {
callback[1].count = 1;
callback[1].total = 2;
}
While compiling its giving an error:
undefined reference to `callback' at 'test_task'
An extern declaration doesn't create the array anywhere. It's merely an instruction to the compiler/linker to look for the variable somewhere.
You must define it, without extern, in some translation unit you will be linking your program with.
A good candidate would seem to be test.c, like this:
volatile callback_task callback[10];
void test_task(void) {
callback[1].count = 1;
callback[1].total = 2;
}
TL;DR It's not the compiler, it's the linker complaining about the callback variable M.I.A. status.
To elaborate, a statement like
extern volatile callback_task callback[10];
tells the compiler that "somewhere there exists" a variable callback with type callback_task [10]. It's a "declaration", It does not "define" a variable on it's own. So, the existence is "known", not "proven".
Later, while linker is searching for the "actual" variable, it does not get one, and hence the error.
Related
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.
I have read this exam code.
"a.c":
int global_1 = 100;
"b.c":
extern int global_1;
int global_2 = global_1 * 2;
int main()
{
return 0;
}
gcc give “error: initializer element is not constant"
I do not write this code, but I want to know why and how to fix.
Thanks.
The problem you are facing is that in order to initialise a variable (global_2 here) it's value (or all values of what it depends on, in your case global_1) need to be known.
When you initialise a variable in a function then it's value only needs to be known at runtime and that is generally the case or you will get an undefined symbol error during compile or link time.
Globals need to be initialised by the compiler during compile time.
extern int global_1;
Says to the compiler that global_1 exists, but not in this compilation unit. It will be accessible after linking. You can use it in functions, but the linker needs to link it first with an object file that actually contains it.
Thus the compiler is unable to initialise it at compile time resulting in the error you see. Linking comes after compiling.
If you need to initialise globals that reference globals in a different compilation unit then you will need to do this in a function. For example the first stem in main().
The error says it all: Initialisers need to be constants.
To fix this you might like to modify your code like this:
int global_2 = 0;
int main()
{
global_2 = global_1 * 2;
The following code is similar to that of question Is there a difference between initializing a variable and assigning it a value immediately after declaration? downvoted twice, so I am at risk ;-)
short i;
i = 2;
It does not compile with MinGW and -std=c99 -- why? The first line is a declaration of identifier i, not a definition of an object. However, the identifier has file scope and thus external linkage by default. It may be declared and defined elsewhere. The second line could be an assignment to that object. But gcc complains about a missing type or storage class and --after guessing the type as int-- about a type conflict.
You say that short i; has file scope, which implies to me that it (edit: and the subsequent i = 2;) is outside a function. Outside a function, i = 2; on its own is complete nonsense; as a statement, it cannot appear outside a function. (edit) As statements cannot appear outside functions, the "assignment" must be a definition. In old C code, a definition without a storage class was an int definition, so your code is equivalent (under those rules, which it looks like GCC is applying) to:
short i;
int i = 2;
which of course is complete nonsense to a C compiler. (end edit)
You can get more-or-less the effect you're after by defining and initializing:
short i = 2;
This does not work if you merely wish to declare an external variable; in that case, put the initialization in the file with the definition, or in one of your functions (as below).
extern short i;
int main(int argc, char **argv) { i = 2; /* more code */ }
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;
I have defined a variable in one file and declared it in another file using the extern keyword. but i have declared it with different datatype..
file1.c
char i;
main()
{
foo();
}
file2.c
void foo()
{
extern int i;
i = 130;
printf("%d", i);
}
In the above program, memory is allocated for 'i' in the main function as char datatype.
And the answer after executing should be negative(-127). But it prints 130. Whatever the value assigned to 'i' in the foo() function is printed not only 130.
"I have defined a variable in one file and declared it in another file using the extern keyword". That is just not true. char i and in main is not in any way related to int i in foo.
The variable you define as char i inside main has no linkage. It cannot be referred to by name from anywhere else in the program besides that main function. There's simply no way to do it in C. It is a local variable.
Your extern int i; declaration inside foo has absolutely no relation to that local char i; variable from main. It declares a completely different, independent variable i. The extern int i declaration in foo refers to a variable i with external linkage, i.e to a global variable i. You are still required to define that i somewhere. That i will have to be defined at file scope (since this is the only way to define a variable with external linkage). If you don't define it your program will not compile.
Entities with external linkage and entities with no linkage live in completely separate worlds. They know nothing about each other and never interact or interfere with each other.
As I said above, the code you posted in your question simply won't compile. The linker will tell you that you forgot to define the int i variable with external linkage that which you declared in used in foo. Yet, your post suggests that the code compiled successfully. This would simply mean that the code you posted is either inaccurate or incomplete. If the code is accurate, then somewhere else in your code you also defined a global variable int i. This is the global variable your foo works with, while the char i in main has absolutely nothing to do with anything.
What you have now, after your edit, is an invalid program again, albeit for a different reason. You defined a global variable char i in file1.c and then you attempted to link to it in file2.c. However, in file2.c you lied to the compiler by telling it that the global variable i has type int, while in reality it has type char.
The behavior of such program is undefined. It is illegal to use inconsistent types when declaring an entity with external linkage. If you declared a global variable of type char in one translation unit, you are not allowed to declare the same global variable with any other type in other translation units.
Some compilers might catch your error and refuse to compile the program. Most C compilers will not catch this error though. Instead the will produce a program that causes undefined behavior. This is what you got in your case. In your case that undefined behavior happened to manifest itself by printing 130 after you assigned 130 to your variable. Why you suddenly find it strange I don't know. Why you expect it to print -127 I don't know either.
Analysis — What is wrong with the code
In your code:
file1.c
int main(void)
{
char i; // Warning: unused variable
foo();
}
file2.c
void foo(void)
{
extern int i;
i = 130;
printf("%d", i);
}
The variable i in main() is wholly unrelated to the i referred to in foo(). The variable i in main() is strictly local to main() and is not passed to foo(); foo() is unable to see that i.
On Mac OS X 10.7.5 with GCC 4.7.1, the files compile separately, but they can't be linked because there is no definition for variable i.
If we move the variable i outside of main(), then the program links:
file2.h
extern void foo(void);
file1.c
#include <stdio.h>
#include "file2.h"
char i = 'A';
int main(void)
{
printf("i = %d (%c)\n", i, i);
foo();
printf("i = %d (%c)\n", i, i);
return(0);
}
file2.c
#include "file2.h"
#include <stdio.h>
void foo(void)
{
extern int i;
i = 130;
printf("i = %d (%c)\n", i, i);
}
This now links and runs, but it invokes undefined behaviour. The linker does not notice that the size of i should be sizeof(int) but is sizeof(char). The assignment in foo(), though, goes trampling out of bounds of the i that is allocated. It doesn't cause visible damage in this program, but that's pure luck.
When I run it on a little-endian machine (Intel x86/64), the output is:
i = 65 (A)
i = 130 (?)
i = -126 (?)
When I ran it on a big-endian machine (SPARC), I got a different result (which isn't very surprising; the behaviour is undefined, so any result is valid):
i = 65 (A)
i = 130 (?)
i = 0 ()
The most significant byte of the 4-byte integer was written over the only byte of the 1-byte character, hence the zero in the third line out output. Note too that it was lucky that the character was allocated an address that was a multiple of 4 bytes; that was not guaranteed and a misaligned address for an int would have caused a bus error (though experimentation suggests that it doesn't happen on SPARC even when i is forced onto an odd address; I'm not sure what is happening).
Synthesis — Correct Handling of extern
The correct way to handle this is to avoid writing external variable declarations such as extern int i; in any source file; such declarations should only appear in a header that is used everywhere the variable needs to be used.
file2.h
extern char i;
extern void foo(void);
With that change in place (and the corresponding extern int i; removed), then the output is self-consistent:
i = 65 (A)
i = -126 (?)
i = -126 (?)
Note the role of the header in keeping both file1.c and file2.c in line with each other. It ensures that the definition in file1.c matches the declaration in file2.h, and the use of file2.h in file2.c ensures that the declaration used there is correct, too. See also What are extern variables in C.
The extern declaration inside foo has absolutely no relation to that local char variable.
As far as I know, extern can be put in front of a variable declaration.
Perhaps this is a bit more confusing.
Doing that tells the compiler you want to share the variable between different .c files.
However, there has to be one .c file where the variable is declared without the extern in front of it.
Note: You're example wouldn't work anyway, as extern has no effect on local variables.
extern is a way to tell the compiler some variable you are using is implemented in another object file that you promise that you will link at link time. It is often used in library header files that involve global variables to tell the compiler that the variable is actually implemented in the library file.
Ex:
file1.c:
int thing;
int bork(int val) {
return thing += val
}
file2.c
extern int thing
int main() {
thing + 2;
}
In the case when i is declared in one file as global variable then only it has external linkage.
Linker only looks for the symbol i which will be resolved at link time ,but types are not resolved by linker so I think it's Undefined Behavior when i is of different type and defind as global variable in one file and extern declaration is done in other file.
You are LYING to the compiler about the size of i. The compiler goes by what you have told it in foo, so you are getting the integer representation. Unfortunately, it won't really work reliably, because you have also written three bytes beyond your char i;
If you add char j = 11; and then print j in main after you call foo();, you'll notice that j is not 11 any more.
Lying to compilers is a bad idea. You get found out sooner or later!
In file1.c, i is defined (and declared implicitly) globally.
char i;
main()
{
foo();
}
file2.c extern is used with a variable i, it’s only declared not defined.
extern char i;
void foo()
{
printf("%d", i);
}