extern declaration and global scope - c

I'm wondering why is this code compiles and run. I thought that if a variable is declared as static (in global scope) it will be accessible only within the file it is declared.
functions.h
static int x = 10;
main.c
#include <stdio.h>
#include "functions.h"
extern int x;
int main()
{
printf("%d", x);
}

Technically, it is indeed declared within the main.c, as this includes the functions.h. If it was a sparate compilation module, you'd be right.
But I'd have suspected that within the same compilation unit extern and staticwould collide with each other. At least it would be worth a warning.

The preprocessor takes the text in functions.h and copies it as is into main.c
After preprocessing (and before compilation) your main.c looks as follows:
#include <stdio.h>
static int x = 10;
extern int x;
int main()
{
printf("%d", x);
}
You will have linker problems if functions.h is included into a second source file, and you try to link both object files into one executable.

when you are including functions.h in main.c , you are actually copy content of function.h in main.c so your final code become something like :
#include <stdio.h>
static int x = 10;
extern int x;
int main()
{
printf("%d", x);
}
So your extern line is redundant.
you can achieve what you want by this
remove #include "functions.h" from main.c
compile function.h using g++ -c function.h
compile main.c using g++ -c main.c
then build g++ function.o main.o -o out
third line would not compile because of static int .

Related

Variable in file 2 is not accessible in file 1

My file1.c is as follows
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("x = %d\n", x);
return 0;
}
And file2.c is as follows
int x = 12;
When I compile both files with gcc -std=c17 file1.c file2.c, I get the error.
error: ‘x’ undeclared (first use in this function)
Now, in my file2.c, x is a global variable. So, even if I don't declare it in file1.c, it should be seen in file1.c. So, why am I getting this error ?
x is a global variable. So, even if I don't declare it in file1.c, it
should be seen in file1.c. So, why am I getting this error ?
No, code in file1.c does not know anything about code in the file2.c. Global variables are visible only in one compilation unit (ie file).
In file1.c you need to add (before main)
extern int x;
This declaration will tell the compiler that somewhere in the project there is a definition of the variable x having the type int
#include <stdio.h>
extern int x;
int main(int argc, char *argv[])
{
printf("x = %d\n", x);
return 0;
}
Like #0___________ said above you need to declare the symbol x so my answer is just spelling it out in a bit more detail. It is customary to move declarations into a file2.h file so it's easy to reference in multiple places (especially if there is more than one symbol):
#ifndef FILE2_H
#define FILE2_H
extern int x;
#endif
Then modify file1.c and file2.c to include it:
#include <stdio.h>
#include "file2.h"
int main() {
printf("x = %d\n", x);
return 0;
}
#include "file2.h"
int x = 12;
Finally, you compile (-std=c17 makes not difference in this sample) and link the two files. Subsequently execute the binary::
$ gcc -std=c17 file1.c file2.c && ./a.out
x = 12
If you prefer a Makefile:
.PHONY: all clean
CFLAGS = -std=c17
all: a.out
clean:
rm -f a.out file1.o file2.o
a.out: file1.o file2.o
$(CC) $^ -o $#
file1.o: file2.h
file2.o: file2.h
and it's then:
$ make && ./a.out
x = 12

Why do we specify header files for targets in Makefile?

I'm trying to understand Makefile. I understand the hole concept of the dependency tree, but why do we include .h files for the .o targets that include certain header file. Here is an example:
// main.c
#include <stdio.h>
#include "math.h"
int main() {
printf("%d\n", magic_number);
printf("%d\n", square(5));
}
// foo.h
const int magic_number = 10;
int square(int);
// foo.c
int square(int value) {
return value*value;
}
# -*- Makefile -*-
all: main
main: main.o foo.o
gcc main.o foo.o -o main
main.o: main.c #foo.h <-----------
gcc -c main.c
foo.o: foo.c
gcc -c foo.c
I commented the part out where I would add the header file. Because that's my question, why does it have to be there? I did some testing and added some more const int variables to the header. Just looking at the Makefile (with commented out foo.h) it would only recompile the main.c file. There it would then access a variable from the header. So why does it look into the header file even thought it's not in the Makefile?
Makefiles track dependencies - in this case it is an explicit dependency.
Specifying that main.o depends on both main.c and foo.h means that any time either file changes, main.o will be rebuilt.
If you didn't have that explicit dependency chain, then you could change foo.h in a way which renders main.c uncompilable, but Make wouldn't know about it so would not rebuild it when it should.
There are tons of ways that a header file can change in such a way that a source file doesn't need to also change, but yet the program is malformed if the source file is not rebuilt. Here's one simple example: say we have this source:
// foo.h
struct foo {
int f;
};
int getfoo(const struct foo* f);
// foo.c
#include "foo.h"
int getfoo(const struct foo* f)
{
return f->f;
}
// main.c
#include "foo.h"
int main()
{
struct foo f = {1};
return getfoo(&f);
}
You compile everything and all is well. Now suppose you modify foo.h like this:
// foo.h
struct foo {
const char* val; // added value
int f;
};
int getfoo(const struct foo* f);
And you modify main.c like this:
// main.c
#include "foo.h"
int main()
{
struct foo f = {"hello", 1};
return getfoo(&f);
}
Now you run make and since you've modified main.c it is recompiled, but since you haven't modified foo.c it is not recompiled.
Now your program will certainly return a bogus value since foo.o thinks that the structure it was passed contains just a single integer, but the structure it was really passed from main() actually has a pointer plus an integer.

Cannot access global variable in one .c file from another .c file [duplicate]

This question already has answers here:
How do I use extern to share variables between source files?
(19 answers)
Access a global static variable from another file in C
(4 answers)
Closed 7 years ago.
To set the scene here - I have 2 .c files, call it a.c and b.c.
I then have 2 header files for each .c file, a.h (which has all function prototypes, and all global variables declared as extern type name;), and b.h which has only function prototypes of b.c as b.c contains no global variables.
I want to access a.c's global variables in b.c, so I have added a statement #include "a.h" in b.c.
Only problem is, I still can't access a.c's global variables in b.c, for example if I want to print. I have a global variable int i; in a.c, and if I do:
i = 5;
printf("%d", i); in b.c, I get an error saying that variable i has not been declared. What am I doing wrong?
The code:
a.c:
#include "b.h"
int i;
int main() {
executeMethod();
return 0;
}
b.c:
#include "a.h"
void executeMethod() {
i = 10;
printf("%d", i);
a.h:
int main();
extern int i;
b.h:
void executeMethod();
makefile:
CFLAGS=-Wall -g
all: main
main: a.c b.c a.h b.h
gcc $(CFLAGS) -o main a.c b.c a.h b.h
clean:
rm -f main
Have also tried without the makefile:
gcc -o main a.c b.c a.h b.h
Thanks.
Edit: it works if I define extern int i; on top of my b.c file, but say I have 60 variables, I would rather have them in a header.h file and just #include "header.h" rather than writing 50 extern statements.
Go ahead and include the header with the ext in both files. Put the definition and initialization in the file that owns the variable. This is okay:
extern int aaa;
int aaa = 1;

Issues with .h files in C

I created a sample .h file in C and it didn't work, for some reason. The files are as follows:
header.c:
#include <stdio.h>
#include "header.h"
int add(int a, int b) {
int tmp=a;
int i;
for(i=0, i==tmp, i++) {
b++;
}
return(b);
}
header.h:
#ifndef HEADER_H
#define HEADER_H
int add(int a, int b);
#endif
main.c:
#include <stdio.h>
#include "header.h"
int main(void) {
int foo=add(1, 2);
printf("%i \n", foo);
return(0);
}
When I try to compile main.c with make and gcc it says that add is undefined. Help!
You need to compile both main.c and header.c into the same executable:
all: main
main: main.o header.o
gcc -o main main.o header.o
header.o: header.c header.h
gcc -c header.c
main.o: main.c header.h
gcc -c main.c
Or for a one-liner without a make file:
gcc -g -o main main.c header.c
Including the header file only includes the function prototype. You need to link the actual definition of add() by compiling separate object files or you can compile them together in a single command line:
gcc -Wall -Wextra header.c main.c -o main
Perhaps, you may want to consider Makefiles for larger projects.
Your add() function has issues:
1) Semi-colons ; are used in for loops, not commas.
2) The condition should be i!=tmp for addition.
This:
for(i=0, i==tmp, i++) { .. }
should be
for(i=0; i!=tmp; i++) { .. }
You need to add header.c to the compile call. You can't just compile main.c.

Compiling multiple C files in a program

I have the following two files:
file1.c
int main(){
foo();
return 0;
}
file2.c
void foo(){
}
Can I compile and link the two files together so the file1.c will recognize the foo function without adding extern?
Updated the prototype.
gcc file1.c file2.c throws: warning: implicit declaration of function foo.
The correct way is as follows:
file1.c
#include <stdio.h>
#include "file2.h"
int main(void){
printf("%s:%s:%d \n", __FILE__, __FUNCTION__, __LINE__);
foo();
return 0;
}
file2.h
void foo(void);
file2.c
#include <stdio.h>
#include "file2.h"
void foo(void) {
printf("%s:%s:%d \n", __FILE__, __func__, __LINE__);
return;
}
output
$
$ gcc file1.c file2.c -o file -Wall
$
$ ./file
file1.c:main:6
file2.c:foo:6
$
You don't need an extern, but file1.c must see a declaration that foo() exists. Usually this declaration is in a header file.
To add a forward declaration without using a header file, simply modify file1.c to:
int foo(); // add this declaration
int main(){
foo();
return 0;
}
You can, but you shouldn't.
Use a header file, file2.h:
// file2.h
void foo(); // prototype for function foo()
Then add:
#include "file2.h"
in file1.c
To compile:
$ gcc -Wall file1.c file2.c -o foo
As a general rule it's better (more robust) to use a header file to define the interface of each module rather than ad hoc prototypes within dependent modules. This is sometimes known as the SPOT (Single Point Of Truth) principle.
It's ugly, but using gcc, you could:
gcc -include file2.c file1.c
-include is a flag to the preprocessor which will include the contents of file2.c at the very top of file1.c. Having said that, it's a poor choice, and breaks down for all but the simplest of programs.

Resources