Use of extern variable in c - c

I have made two files in c i.e. file1.c file2.c. In file1.c I wrote
#include< stdio.h >
int s=10;
void main()
{
printf("This is file 1");
}
In file2.c
include < stdio.h >
extern int s;
void main() {
printf("%d",s);
}
When I compiled file2.c in ubuntu terminal I got undefined referenced to s error.
How can I resolve this error?

In the second case,
extern int s;
tells the compiler that "somewhere there" exists a variable s which has type int, but it actually does not "define" the variable. So, the linker has no clue where to find the variable, it cannot find the variable and throws the error.
You need to have a definition of the variable, either in a separate translation unit (the purpose of using extern) or in the same translation unit (if you want).

In file1.c
#include <stdio.h>
void myfunction( void );
int s=10;
void myfunction()
{
printf("This is file 1");
}
In file2.c
#include <stdio.h>
void myfunction( void );
extern int s;
int main( void )
{
myfunction();
printf("%d",s);
}
then compile (the example uses gcc
gcc -g -Wall -Wextra -pedantic -Wconversion -std=gnu11 -c file1.c -o file1.o
gcc -g -Wall -Wextra -pedantic -Wconversion -std=gnu11 -c file2.c -o file2.o
then link using:
gcc -g file1.o file2.o -o myexec
then run it as
./myexec
Of course, if your using Visual Studio, the command line statements will be slightly different

Related

Linking extern variables using multiple library in C

In my project, I have two libraries and one program.
Lib1.c and Lib1.h are two files of first library(Lib1.so).
Lib2.c and Lib2.h are two files of second library(Lib2.so).
prog.c is the main file of program(prog).
The program(prog) is linked only to the second library(Lib2.so) and the second library(Lib2.so) is linked to the first library(Lib1.so).
In Lib1.c, I have a declaration of global variable (int var = 0;) and in Lib1.h, I have a declaration (extern int var;).
In Lib2.h, I have a declaration (extern int var;) in order to use var variable in main program.
In main() function, I include the Lib2.h in prog.c file and I have a declaration (var = 5;)
Lib1.c :
#include <stdio.h>
#include "Lib1.h"
int var = 0;
int funct(void)
{
printf("hello world \n");
return 0;
}
Lib1.h :
extern int var;
int funct(void);
Lib2.c :
#include <stdio.h>
#include "Lib2.h"
int funct2(void)
{
printf("Library 2 \n");
funct();
return 0;
}
Lib2.h :
#include "Lib1.h"
extern int var;
int funct2(void);
prog.c :
#include <stdio.h>
#include "Lib2.h"
int main()
{
var = 5;
printf("===>var=%d\n", var);
funct2();
return 1;
}
Commands :
gcc -c -Wall -Werror -fpic Lib1.c
gcc -shared -o Lib1.so Lib1.o
gcc -c -Wall -Werror -fpic Lib2.c
gcc -shared -o Lib2.so Lib2.o -ldl /home/test/Lib1.so
gcc prog.c -o prog -ldl /home/test/Lib2.so
When I try to compile the program(prog.c), I get an error in the link step as below.
/usr/bin/ld: /tmp/ccKaq16a.o: undefined reference to symbol 'var'
/home/test/Lib1.so: error adding symbols: DSO missing from command line
Is there a way to use var variable in the main function when its defined in the first library?
You link your program against Lib2 but not Lib1. You need to add that as well. You also don't need to explicitly link Lib1 when you create Lib2
gcc -c -Wall -Werror -fpic Lib1.c
gcc -shared -o Lib1.so Lib1.o
gcc -c -Wall -Werror -fpic Lib2.c
gcc -shared -o Lib2.so Lib2.o
gcc prog.c -o prog /home/test/Lib2.so /home/test/Lib1.so

Linking to an executable on OSX

On Windows it is possible to dynamically link to an executable with exported symbols. For example following code:
// main.c
void __declspec(dllexport) interface_function() {}
int main() {}
// ext.c
void interface_function();
void extension_function() {
interface_function();
}
With
cl.exe main.c
cl.exe ext.c /LD /link main.lib
would produce an executable main.exe, a static library main.lib for implicit linking, and a dynamic library ext.dll.
Similar behavior can be achieved in OSX with shared libraries:
// main.c
void interface_function() {}
int main() {}
// ext.c
void interface_function();
void extension_function() {
interface_function();
}
With
gcc main.c -o main
gcc ext.c -bundle -bundle_loader main -o ext.bundle
it is virtually equivalent to the Windows setup.
But for dynamiclib:
> gcc ext.c -dynamiclib -o ext.dylib
and shared:
> gcc ext.c -shared -o ext.so
I cannot get them to work because of undefined symbols on one hand and unable to load an executable with -l flag on the other.
I can let them resolve undefined symbols in runtime with -undefined dynamic_lookup. But this is not a sustainable way because all the link errors are now happening in run-time instead.
Is there a way to provide the list of symbols to dynamically load from an executable when linking as -shared and -dynamiclib?
Yes this is possible, but then you'll want to create a bundle rather than a shared library (see this answer for more detail).
If you have a main application like so:
#include <stdio.h>
#include <dlfcn.h>
int func(void)
{
return 42;
}
int main(void)
{
void *dl = dlopen("plugin.so", RTLD_LOCAL);
if(!dl) return -1;
int (*derp)(void) = dlsym(dl, "derp");
if(!derp) return -1;
printf("derp(): %i\n", derp());
return 0;
}
clang -o main main.c -Wall -Wl,-export_dynamic
Then you can compile bundles against it like so:
int func(void);
int derp(void)
{
return -func();
}
clang -o plugin.so plugin.c -Wall -bundle -bundle_loader ./main

Referencing global symbols from shared library loaded with dlopen

I have a shared library which I want to access symbols from the main program. For example:
main.c
#include <stdio.h>
void bar(void) { puts("bar"); }
extern void foo(void);
int main(void) {
foo();
return 0;
}
foo.c
#include <stdio.h>
extern void bar(void);
void foo(void) {
puts("foo");
bar();
}
I compile and run like:
gcc -c -fpic foo.c
gcc -shared -o libfoo.so foo.o
gcc -L$(pwd) -o test main.c -lfoo
./test
And I get the output I expect:
foo
bar
However, I must use dlopen() and dlsym() because I want to have control over when the library is loaded. The changed files are:
main.c
#include <stdio.h>
#include <dlfcn.h>
void bar(void) { puts("bar"); }
int main(void) {
void *handle = dlopen("./libfoo.so", RTLD_LAZY);
void (*foo)(void) = (void(*)(void))dlsym(handle,"foo");
foo();
return 0;
}
foo.c
#include <stdio.h>
#include <dlfcn.h>
extern void bar(void);
void foo(void) {
puts("foo");
bar();
}
I instead compile and run with:
gcc -c -fpic foo.c
gcc -shared -o libfoo.so foo.o
gcc -o test main.c -ldl
./test
However, this time I get the output
foo
./test: symbol lookup error: ./libfoo.so: undefined symbol: bar
How can I reference symbols in the main program from libfoo?
You have to add the -rdynamic option when linking test:
gcc -o test main.c -ldl -rdynamic
From here:
-rdynamic
Pass the flag -export-dynamic to the ELF linker, on targets that support it. This instructs the linker to add all symbols, not only used ones, to the dynamic symbol table. This option is needed for some uses of dlopen or to allow obtaining backtraces from within a program.

Linking multiple .c files

I have a C file named first.c in which I define an array and call a function which is defined in a C file named second.c. This is how first.c looks:
int main(void)
{
int array[100];
myFunc(*array);
}
second.c on the other hand looks like this:
void myFunc(int array)
{
...
}
But anytime I try to compile these, second.c gives me errors as if it had no idea about the array I passed to its function as an argument. I guess the function doesn't know that at the linking stage. I compile these like this:
gcc -O2 -std=c99 -Wall -pedantic -lm second.c -c
gcc -O2 -std=c99 -Wall -pedantic first.c -c
gcc second.o first.o -o finished
But that's just what I came up with and of course it doesn't work. I guess a Makefile would be in place, but I'm not sure how to implement it.
Your issue may lie in that the received value is not a pointer- so change void myFunc(int array) to void myFunc(int* array).

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

Resources