Why are function definitions implicitly external in C? - c

I read that the extern keyword is implicit in the context of functions, so unless you specify otherwise using the static keyword (which if I'm not mistaken is basically a completely separate concept from the static that variables employ—they just share a keyword), they are visible to all object files. This makes sense; having the declarations be implicitly external, while technically unnecessary when the declarations are in the same file as the definition, is useful because the programmer doesn't have to type extern every time they want to use a function out of its defining file, which is more often the case than not. What seems odd to me is that it is implicit for the declarations and the definition.
With a variable, I don't need to include an extern for the definition, and in fact, while I can do this without error, my compiler gives me a warning for it.
For example, I can have mylib.h:
int var = 5;
//it isn't necessary to write this as
//extern int var = 5;
//my compiler even warns against it
and test.c
#include "mylib.h"
extern int var;
I would normally assume the implicit extern for functions to be the same, that is, if I defined int func(int par) in mylib.h, there would not be an implicit extern before it, but there would be an implicit extern for any declaration of it (such as if I declared it for use in test.c).
It also doesn't make much sense from the perspective of the extern keyword being used as a way of telling the compiler to look elsewhere for the definition, when the definition would never be external of the file it is in.
I feel like I'm missing something here.

If you use int x = 10; in any header file, then you are entering into trouble, because if you include the same header file in any other file (.c or .h) that is linked with test.c then you will get an error redefinition of variable x.
You can try that for yourself.
So always keep extern int x; in a header file,
and define it int x = 10; in any .c file.
So, in this case, if you include the header file in multiple places, it is fine, because the header file only has a declaration and you can declare the same variable in multiple places without any problem.
you can try this sample program to test the error multiple definition of `global_value'
test.h
extern int global_value;
test.c
#include <stdio.h>
#include "test.h"
int global_value = 10;
int test_func()
{
printf("golbal_value = %d", global_value);
global_value = 20; // changed here, reflect in main after test_func call
}
main.c
#include <stdio.h>
#include "test.h"
int main()
{
test_func();
printf("global_value = %d\n", global_value);
return 0;
}
the above program works perfectly. to get the error bring that extern int global_value; to test.c and int global_value = 10; to test.h and compile all together gcc test.c main.c

Related

Correct use of extern when using global variables imported from standard library?

I am trying to learn the use of the extern keyword. As an example I am using the getopt C library function. From my understanding of the extern keyword, it used to indicate to the compiler that a certain variable that has been defined in another file is going to be used. So whenever I am going to be using the getopt variables like opterr, optind, etc, should I(would it be wrong of me to) do this:
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
extern int optopt;
extern int opterr;
extern int optind;
extern char *optarg;
int main(int argc, char **argv) {
/* code using getopt */
}
When I looked at the manpage for getopt(3), I saw these declarations already mentioned under #include <unistd.h>. So I thought that these were declared in that header file but when I looked into the header file itself, there was no such declaration.
So my question is: is there anything wrong with using these statements at the beginning even if for the sake of improving readability for someone who doesn't how getopt works. Also, at the end of the day if the linker is going to resolve references, anyways, is there any reason to use extern at all?
Also, at the end of the day if the linker is going to resolve references, anyways, is there any reason to use extern at all?
The extern keyword can tell the compiler that an unknown symbol is going to be provided by another file.
Consider the situation where we have file1.c with:
int myvariable;
And file2.c with:
#include <stdio.h>
int main() {
myvariable = 10;
printf("myvariable is %d\n", myvariable);
return 0;
}
Attempting to compile this will fail with:
file2.c: In function ‘main’:
file2.c:4:5: error: ‘myvariable’ undeclared (first use in this function)
4 | myvariable=10;
Adding the appropriate extern declaration to file2.c allows us to compile it without errors:
#include <stdio.h>
extern int myvariable;
int main() {
myvariable = 10;
printf("myvariable is %d\n", myvariable);
return 0;
}
Header files can be nested.
unitstd.h includes many other files, the specific declarations you are looking for are in getopt.h,
These statements do not improve readability, they decrease it by adding duplicate garbage code.
A programmer familiar with C but not with getopt function would think these are your custom variables, not part of the standard library, because nothing in the standard library should be redeclared.
The linker is the last step in building the executable.
The external keyword is for the compiler to know the names and types, so it can build code with references for the linker to resolve later.
While it's OK to have more than one declaration for a function or object, as a rule it's best not to redeclare anything declared in a standard library header. It might cause issues if what you declared doesn't exactly match what's in the headers.
Also, just because the man pages say to include unistd.h doesn't necessarily mean the declaration is in that specific file. The declaration in question could be in a file that unistd.h includes. All it means is that including unistd.h will give you the required declaration.

calling a function from a .h file [duplicate]

This question already has answers here:
How do I use extern to share variables between source files?
(19 answers)
Closed 8 years ago.
file1.c => includes file1.h
file1.h => has a struct:
typedef struct {
unsigned char *start;
unsigned int startInt;
}debugPrint;
file1.c => creates a struct object:
debugPrint dp;
file1.c => an int is given into struct:
dp.startInt = 10;
file1.c => has a function:
void function1(debugPrint dp) {
printf("%d", dp.startInt);
}
file2.h => has a function call to file1.c function which is declared before the call:
void function1(void);
function1();
Questions is:
Is it ok that the file2.h calls a function from file1.c
how can i pass the dp.startInt value to file2.h so that the value 10 that was set into dp.startInt in file1.c can be used in the funtion call in file2.h ?
It is needed to be called from file2.h since this file handles dynamic variable exchange between a html page and the file2.h file => data from file2.h function call via file1.c is sent to Html page. But i wont go more into the passing variable to html page since i don't know how it is made. It is a mechanism of openPicus web server example.
But if you know a good solution for this one. i would appreciate it. I'm not so familiar with this kind of code so that is also an issue here :)
But since i think this description is not good enough, here is the files:
file1.c:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include "test1.h"
// Define printStruct
void printStruct (debugPrint dp) {
printf("%u", dp.startInt);
}
int main ()
{
dp.startInt = 10;
getch();
}
file1.h:
typedef struct {
// For the motorEncoder value
unsigned char filename[20];
char ownMsg[10];
unsigned char *start;
unsigned char *timeInSeconds;
unsigned char *distanceInCm;
unsigned char *numberOfShots;
unsigned char *shutterCompensation;
unsigned char *direction;
unsigned char *cancel;
unsigned char *dutyCycle;
unsigned int cancelInt;
unsigned int startInt;
unsigned int dutyCycleInt;
unsigned int directionInt;
}debugPrint;
// Create struct object called dp
debugPrint dp;
// declare printStruct
void printStruct (debugPrint dp);
file2.h: (this file is totally needed to pass the dynamic values) I didn't put any includes since im not sure how i should include the .h files and from where i should include them.
// Call printStruct function
printStruct(dp);
part of file2.h actual code: (AND YES file2.h A HEADER FILE). FOR ME THIS SEEMS LIKE THE FUNCTIONS ARE FIRST DECLARED AND THEN ONE OF THEM IS USED IN THE H FILE => the HTTPPrint() function from where a function called HTTPPrint_stepCounter(); is called. That function is defined then in file1.c and it just prints some dynamic data to a http page. And as said this is how openPicus has done it and i am just trying to modify it.
void HTTPPrint(DWORD callbackID);
void HTTPPrint_led(WORD);
void HTTPPrint_stepCounter(void);
void HTTPPrint(DWORD callbackID)
{
switch(callbackID)
{
case 0x00000017:
HTTPPrint_led(0);
break;
case 0x00000059:
HTTPPrint_stepCounter();
break;
default:
// Output notification for undefined values
TCPPutROMArray(sktHTTP, (ROM BYTE*)"!DEF", 4);
}
return;
}
void HTTPPrint_(void)
{
TCPPut(sktHTTP, '~');
return;
}
Some tips for someone new to the C language:
There's an important difference between definition and declaration.
Definition is what actually creates the function or variable. Each function must be defined exactly once. Either in a *.c source file, or in a library.
Declaration creates an entry in the symbol table, that says the function or variable exists... somewhere... and here's its data type. Declarations can be duplicated without any effect.
We put function definitions in *.c source files. (And also in libraries, but that's an advanced build topic...)
We put public or extern function declarations in *.h header files.
We put shared extern variable declarations in *.h header files, so that other source units can share the same variable.
We put shared typedef structure declarations in *.h header files, so that other source units can share the same data type.
We do not put variable declarations in *.h header files if they aren't extern, or if they are initialized. The initial value belongs in the *.c file.
Function definitions usually don't belong in a *.h header file, because it's possible in a large project, that the header file could be included (read by the compiler) more than once. That would cause a compiler error, because then there would be more than one definition of that function. Even if it's literally a repeat of the same source code, there can be only one.
The quote about file2.h having a function call to file1.c function is not correct, function1(); could be either a declaration or a function call depending on context:
// declaration of a function named foo
void foo(void);
//
// declaration of a function named bar
// equivalent to declaring void bar(void);
bar();
//
// definition of a function named foo
void foo(void)
{
// call (or invoke) the function named bar
bar();
}
Another small point, about arrays: it's pretty strange to declare an array of one element debugPrint dp[1], since that declaration creates an object that will be referred to as dp[0]. This makes me think you may be trying to avoid the use of pointers... it would be more straightforward to just declare debugPrint dp and then the object is referred to as dp. Arrays make sense if you have more than one related object of the same type, but for just one object, it's a pretty unusual usage.
C is a very flexible programming language that gives free access to lots of low-level tricks. Both a blessing and a curse... For someone just getting started with the language, it's important to read other people's code examples as much as you can, to help learn how things are usually done. There are lots of extremely clever ways to use the language (e.g. Duff's Device) but in most cases, you're better off sticking with the most straightforward and customary way of solving the problem.
See also: What is the difference between a definition and a declaration?
You claim that file2.h contains:
void function(void);
function1();
But these lines refer to two different functions.
This problem is now fixed; both names are function1
If the function1(); appears outside any function, it is a (very sloppy) function declaration, not a function call. If it is inside some function, what is that function definition doing inside the header file. It would need to be an inline function to have much legitimacy.
The problem below is now fixed; the types are consistent.
Additionally, you say: an integer is given into struct: dp[1].startInt = 10;. The compiler complains that you shouldn't assign integers to pointers (since startInt is declared as a pointer, not an int). You need to get your code to compile without such complaints.
... There are two versions of the structure defined, one at the top of the question where startInt is an unsigned int *startInt; and one later on where the declaration is unsigned int startInt. Please make your question self-consistent! ...
This problem has been fixed now; dp is a simple structure.
Also note that you created debugPrint dp[1]; so your initialization is trampling out of bounds; the maximum valid index for the array is 0.
If code in file2.c needs to access the internals of the structure type declared in file1.h, the header file1.h should be included in file2.c. You can declare your dp array in the header too. A header should include other headers only if the functions it defines expose types defined in the other headers. For example, if the structure defined in file1.h included a FILE *db_fp; element, then file1.h should #include <stdio.h> to ensure that the code in file1.h would compile regardless of what else the code using file1.h includes.

Compiling without including a header file

In a particular C project, a file say file1.c uses a function say FUNCTION2(). The FUNCTION2() is declared in file2.c. An extern declaration of FUNCTION2() is there in file1.h
The file1.c adds only file1.h.
In file1.h, the file2.c/file2.h is not added. Still the compilation is successful and the functionality is working.
In the compilation list of the project, file2.c/file2.h is compiled first. But is that possible to call functions without adding the header file?
You can, but I wouldn't advise it. You have arranged things to force the compiler to exploit implicit declaration:
int main()
{
foo(2); /* The compiler emits this by implicit declaration. */
return 0;
}
int foo(int x)
{
return x;
}
In your explicit case, extern is telling the compiler to expect foo to come from a different compilation unit.
The standard thing to do would be to put a prototype of foo in a header and include that.

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;

Declaring a struct in a header makes it global

There are three files:
source1.c
source2.c
header.h
The two source-files includes the header.
This is the code of the header:
struct
{
int a;
int b
} x;
What happens now is that the struct becomes global and the two source-files now shares the struct called x. Why does this happen?
I know that if you write the following code it will make two global variables. One for each of the source-files. (they don't share the globals)
int x = 0;
The last piece of code makes sense to me but i really don't understand the one with the struct..
EDIT:
Hmm everybody here think I should get linker errors. My current code is for an embedded system (nxtOSEK). I'll try to convert it to a regular C program later.
EDITEDIT:
I'm back with examples in regular C. As you can see it is not only possible with structs but also with regular variables.
source1.c
#include "header.h"
int main(void)
{
f();
x = 1;
f();
}
source2.c
#include "header.h"
void f()
{
printf("source2: %i\n", x);
}
header.h
#include <stdio.h>
int x;
Output
source2: 0
source2: 1
Note that x must not be declared for it to work or it gives a linker error like everyone here said. (I don't know why it work with the embeded system..)
It also looks like I misread Eric Postpischil's answer which looks correct.
An external declaration of an object identifier at file scope that has an initializer is a definition. The declaration int x = 0; is a definition because x is initialized.
An external declaration of an object identifier at file scope that does not have an initializer is a tentative definition. The declaration struct {…} x; is a tentative definition because x is not initialized.
Multiple definitions at link time cause an error.
Multiple tentative definitions at link time may be coalesced to a single definition, which is initialized with zero. This was traditional Unix behavior and was the default behavior with GCC prior to version 10; GCC marked tentative definitions as “common” symbols by default. With GCC version 10 and later, multiple-definition errors may result. The old behavior can be selected with the -fcommon command-line switch to GCC.
If you change int x = 0; to int x;, you will not a get a link error while using build tools that treat tentative definitions as common symbols. If you change struct {…} x; to struct {…} x = {0};, you will get a link error.
The piece of code below
struct
{
int a;
int b;
} x;
declares a variable x of type struct with no tag. This is OK for a static struct that you plan to use in a single compilation unit, but if you plan to share a struct among several .c files, you should not do it like that. Instead, you should define a tag for your struct or make a typedef for it, and declare the variable of that type separately, using the srtruct my_struct syntax.
Here is an example:
Put this struct declaration in the header:
struct a_and_b
{
int a;
int b;
};
Put this variable declaration in the .c file:
static struct a_and_b x;
Now x is no longer global: you can access it inside your .c file, but it is not visible from the outside. If you want to make it global, but avoid linker errors, add
extern struct a_and_b x;
to the header, and remove static from the declaration in the .c file.

Resources