Variable in file 2 is not accessible in file 1 - c

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

Related

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.

Undefined reference to global variable during linking

I am trying to compile a program which is divided into 3 modules, corresponding to 3 source files: a.c, b.c, and z.c. z.c contains the main() function, which calls functions in a.c and b.c. Furthermore, a function in a.c calls a function in b.c, and viceversa. Finally, there is a global variable count which is used by the three modules and is defined in a separate header file, global.h.
The code of the source files is the following:
a.c
#include "global.h"
#include "b.h"
#include "a.h"
int functAb() {
functB();
functA();
return 0;
}
int functA() {
count++;
printf("A:%d\n", count);
return 0;
}
b.c
#include "global.h"
#include "a.h"
#include "b.h"
int functBa() {
functA();
functB();
return 0;
}
int functB() {
count++;
printf("B:%d\n", count);
return 0;
}
z.c
#include "a.h"
#include "b.h"
#include "global.h"
int main() {
count = 0;
functAb();
functBa();
return 0;
}
The header files:
a.h
#ifndef A_H
#define A_H
#include <stdio.h>
int functA();
int functAb();
#endif
b.h
#ifndef B_H
#define B_H
#include <stdio.h>
int functB();
int functBa();
#endif
global.h
#ifndef GLOBAL_H
#define GLOBAL_H
extern int count;
#endif
And, finally, the makefile that reproduces my error:
CC = gcc
CFLAGS = -O3 -march=native -Wall -Wno-unused-result
z: a.o b.o z.o global.h
$(CC) -o z a.o b.o z.o $(CFLAGS)
a.o: a.c b.h global.h
$(CC) -c a.c $(CFLAGS)
b.o: b.c a.h global.h
$(CC) -c b.c $(CFLAGS)
z.o: z.c a.h global.h
$(CC) -c z.c $(CFLAGS)
With this, I can compile the objects a.o, b.o, and z.o fine, but, when linking with make z, I get undefined reference to 'count' in all of them:
z.o: In function `main':
z.c:(.text.startup+0x8): undefined reference to `count'
a.o: In function `functAb':
a.c:(.text+0xd): undefined reference to `count'
a.c:(.text+0x22): undefined reference to `count'
a.o: In function `functA':
a.c:(.text+0x46): undefined reference to `count'
a.c:(.text+0x5b): undefined reference to `count'
b.o:b.c:(.text+0xd): more undefined references to `count' follow
collect2: ld returned 1 exit status
I managed to reproduce the error in my actual code in this minimal example, so I guess there is a problem in the dependencies between modules, but I can't spot it. Can anyone point me in the right direction?
Change your z.c to
#include "a.h"
#include "b.h"
#include "global.h"
int count; /* Definition here */
int main() {
count = 0;
functAb();
functBa();
return 0;
}
From global.h, all your files inherit the declaration of variable count but the definition is missing from all files.
You must add the definition to one of the file as int count = some_value;
You have declared count, not defined it.
extern is a part of declaration, not a definition.
To be explicit, extern is a storage-class specifier and used at declaration.
You need to define int count somewhere in your source files.
You have to add int count; to your z.c file.
This because of declaring a variable in header file as extern tells to the compiler that the variable will be declared in another file, but the variable is not declared yet and will be resolved b linker.
Then you need to declare the variable somewhere.

multiple definition in g++?

The code is as follows:
global.h
#ifndef GLOBAL_H
#define GLOBAL_H
#include <stdio.h>
int test;
void test_fun(void);
#endif
global.c
#include "global.h"
void test_fun()
{
printf("%d\n", test);
}
main.c
#include "global.h"
int main(void)
{
test_fun();
test = 1;
printf("%d\n", test);
}
Makefile using gcc compiler
main: main.o global.o
gcc -o main main.o global.o
main.o: main.c global.h
gcc -c main.c
global.o: global.c global.h
gcc -c global.c
clean:
rm -f global.o main.o main
This works well.
However, when I change my code to C++, as follows:
global.h
#ifndef GLOBAL_H
#define GLOBAL_H
#include <iostream>
int test;
void test_fun(void);
#endif
global.cpp
#include "global.h"
void test_fun()
{
cout << test
}
main.cpp
#include "global.h"
int main(void)
{
test_fun();
test = 1;
std::cout << test;
}
Makefile using g++ compiler
main: main.o global.o
g++ -o main main.o global.o
main.o: main.cpp global.h
g++ main.cpp
global.o: global.cpp global.h
g++ global.cpp
clean:
rm -f global.o main.o main
The code above throws the output:
global.o:(.bss+0x0): multiple definition of `test'
What makes the different here?
You've int test; in a header which is included in 2 TUs, hence the error. Both the translation units main.c (or .cpp depending upon the compiler used) and global.c have global.h included, which leads to two definitions of the same variable in two object files, thus the linker error.
Pass test as an arguement to test_fun, thereby avoiding the usage of a global.
If you absolutely have to share the variable between the TUs, then remove int test; from global.h and in main.cpp do
int test;
and in global.cpp do
extern int test;
As an aside, since it's a global variable, test would be initialized to 0 and hence in main when you test_fun();, it should print 0 and then after setting it to 1, it'll print 1.
It's illegal in both C and C++ from a language standpoint, but as for why it works with a C compilers (like GCC) is because they implement a common extension, a legacy cruft.
... You are using a different programming language

extern declaration and global scope

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 .

Is this correct usage of weakref?

I want to allow the redefinition of a function in a .c file that is already defined in a header file. According to GCC manual on the weakref attribute:
The effect is equivalent to moving all references to the alias to a separate translation unit, renaming the alias to the aliased symbol, declaring it as weak, compiling the two separate translation units and performing a reloadable link on them.
Which sounds like exactly what I want to do.
However, the following example does not compile with error:
tpp.c:18:13: error: redefinition of ‘foo’
tpp.c:6:13: note: previous definition of ‘foo’ was here
#include <sys/types.h>
#include <stdio.h>
/* this will be in a header file */
static void foo(void) __attribute__ ((weakref ("_foo")));
static void _foo(void)
{
printf("default foo\n");
}
/* in a .c file #including the header mentioned above */
#define CUSTOM_FOO
#ifdef CUSTOM_FOO
static void foo(void)
{
printf("user defined foo.\n");
}
#endif
int main(int argc, char **argv)
{
printf("calling foo.\n");
foo();
}
Am I using this correctly? What am I missing?
gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
As far as I understand that you need to define that function as extern.
Then it work for me as follows:
user#horst:$ cat weakref.c
#include <sys/types.h>
#include <stdio.h>
/* this will be in a header file */
extern void foo(void) __attribute__ ((weak, alias ("_foo")));
void _foo(void)
{
printf("default foo\n");
}
int main(int argc, char **argv)
{
printf("calling foo.\n");
foo();
}
user#horst:$ gcc weakref.c
user#horst:$ ./a.out
calling foo.
default foo
user#horst:$ cat weakrefUser.c
#include <stdio.h>
/* in a .c file #including the header mentioned above */
#define CUSTOM_FOO
#ifdef CUSTOM_FOO
void foo(void)
{
printf("user defined foo.\n");
}
#endif
user#horst:$ gcc -c weakrefUser.c
user#horst:$ gcc -c weakref.c
user#horst:$ gcc weakref.o weakrefUser.o
user#horst:$ ./a.out
calling foo.
user defined foo.
Note1: It does not work with static functions, for the weak attribute, it need to be global.
Note2: Weak symbols are "only" supported for ELF targets.
Since I wanted to use weak or weakref, and the existing answer seemed incomplete, I decided to write up the options, and try to explain.
There are apparently three basic options:
Use weakref. In this case, you write a static definition of a different name referencing the name you want, and it may or may not be null. You need to test the function before calling it. In this case, the alias option must be included either explicitly or as a parameter on weakref.
Use weak without alias. In this case, things are simple and public. Again, it may or may not be null, and you must test it before calling it.
Use weak and alias. In this case, the call and the declared alias must (apparently) be in the same source file. In this case, there is always a definition for the symbol, so you don't need to test for it. If there is an external definition of the name, you will get that in leiu of the alias.
In C++, when providing an alias name, the name must be the mangled form. (This was relevant to me, not to OP.)
My test sources are:
cat weakref.c :
#include <stdio.h>
static void fooref(void) __attribute__((weakref("foo")));
int main(int argc, char **argv)
{
if (fooref) {
printf("calling foo.\n");
fooref();
} else {
printf("no foo to call. (do something default-ish)\n");
}
}
cat weak.c :
#include <stdio.h>
#include "header.h"
int main(int argc, char **argv)
{
if (foo) {
printf("calling foo.\n");
foo();
} else {
printf("no foo to call. (do something default-ish)\n");
}
}
cat weakalias.c :
#include <stdio.h>
#include "header.h"
extern void foo(void) __attribute__ ((weak, alias ("defaultfoo")));
void defaultfoo(void)
{
printf("default foo\n");
}
int main(int argc, char **argv)
{
printf("calling foo.\n");
foo();
}
cat header.h :
extern void foo(void) __attribute__ ((weak));
cat Makefile :
EXES = weakref weakreffoo weakalias weakaliasfoo weak weakfoo
all : ${EXES}
clean :
-rm ${EXES} *.o
weakref : weakref.o
gcc -o $# $^
weakreffoo : weakref.o foo.o
gcc -o $# $^
weakalias : weakalias.o header.h
gcc -o $# $^
weakaliasfoo : weakalias.o foo.o header.h
gcc -o $# $^
weak : weak.o header.h
gcc -o $# $^
weakfoo : weak.o foo.o header.h
gcc -o $# $^
cat foo.c :
#include <sys/types.h>
#include <stdio.h>
void foo(void)
{
printf("custom foo\n");
}
My output reads:
$ ./weakref
no foo to call. (do something default-ish)
$ ./weakreffoo
calling foo.
custom foo
$ ./weak
no foo to call. (do something default-ish)
$ ./weakfoo
calling foo.
custom foo
$ ./weakalias
calling foo.
default foo
$ ./weakaliasfoo
calling foo.
custom foo
$
I initially decided on weakref, but am now leaning towards weak.

Resources