How can I access and modify a global variable across multiple files? - c

Like the title says, I want to create a system where two programs can access and modify the same global variable.
I've created a directory that has the files 1.c, 2.c, foo.c, and foo.h.
1.c:
#include <unistd.h>
#include <stdio.h>
#include "foo.h"
int main(){
printf("foo is %d\n", foo);
sleep(7);
printf("now foo is %d\n", foo);
}
2.c:
#include <stdio.h>
#include "foo.h"
int main(){
increment();
printf("2.c is incrementing foo. foo is now %d\n", foo);
}
foo.h:
#ifndef FOO_H
#define FOO_H
extern int foo;
void increment(void);
#endif
foo.c:
#include <stdlib.h>
#include "foo.h"
int foo = 5;
void increment(){
++foo;
}
I compile with the following compilation commands:
gcc -c foo.c
gcc 1.c foo.o -o 1.out
gcc 2.c foo.o -o 2.out
And then I run it with ./1.out ./2.out, ensuring that 2.out runs before the sleep() finishes in 1.out. The result is the following:
./1.out
foo is 5
now foo is 5
./2.out
2.c is incrementing foo. foo is now 6
My theory is that when 1.c and 2.c are linked with foo.o, they both get their own local copies of foo, and thus when one program modifies foo the other program's version goes unmodified. Is it possible to create one global variable that can be shared and modified across multiple files?

In C, global variables are global to the execution unit (process), not global to the execution environment (system). Standard C does not provide a mechanism to share memory between processes. However, your platform (Linux, Windows, MacOS, etc.) probably does. Look up "shared memory".

Related

Undefined reference to extern function - C

I'm currently working on a C project, but I'm stuck on what seems to be a simple problem...
My files are main.c, main.h, fun1.c, fun2.c and fun3.c.
main.h is included in main.c, fun1, fun2 and fun3 (respectively in fun1.C, fun2.c and fun3.c files) are used by a function in main.c, and the fun1, fun2 and fun3 functions are declared in main.h like that:
extern int fun1(unsigned);
extern int fun2(int, int, int);
extern int fun3(int, int);
But when I try to compile the code, I get these errors
main.c:12: undefined reference to 'fun1'
main.c:17: undefined reference to 'fun2'
main.c:25: undefined reference to 'fun3'
Did I miss something about the way extern works? Thanks for your answers.
The project is actually a lot more complex since I am working on a kernel, but I simplified it. This is a work that my teacher gave me, and I'm trying to modify the code as less as possible, that's why I'm sticking to the use of extern.
UPDATE
As the problem seems to lie somewhere else, I'm going to show you my file system.
My files are sem.c, sem.h, semget.c, semctl.c and semop.c.
sem.h is included in sem.c, semget, semctl and semop (respectively in semget.C, semctl.c and semop.c files) are used by a function in sem.c, and the semget, semctl and semop functions are declared as extern in sem.h (same as before, just changed back the names).
At some point in the makefile (don't ask me what the makefile is doing, I have no idea because of its complexity), the file syscalls.c is used:
#include <nanvix/const.h>
#include <nanvix/syscall.h>
/*
* System calls table.
*/
PUBLIC void (*syscalls_table[NR_SYSCALLS])(void) = {
(void (*)(void))&sys_alarm,
...
(void (*)(void))&semget,
(void (*)(void))&semctl,
(void (*)(void))&semop
};
The syscalls.c file include the syscall.h file:
#ifndef NANVIX_SYSCALL_H_
#define NANVIX_SYSCALL_H_
#include <nanvix/const.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/times.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <ustat.h>
#include <utime.h>
/* Number of system calls. */
#define NR_SYSCALLS 51
/* System call numbers. */
#define NR_alarm 0
#define NR_brk 1
...
#define NR_semget 48
#define NR_semctl 49
#define NR_semop 50
#ifndef _ASM_FILE_
/* System calls prototypes. */
EXTERN unsigned sys_alarm(unsigned seconds);
EXTERN int sys_brk(void *ptr);
...
EXTERN int semget(unsigned key);
EXTERN int semctl(int semid, int cmd, int val);
EXTERN int semop(int semid, int op);
#endif /* _ASM_FILE_ */
#endif /* NANVIX_SYSCALL_H_ */
The exact error is what follows:
sys/syscalls.o:(.data+0xc0): undefined reference to `semget'
sys/syscalls.o:(.data+0xc4): undefined reference to `semctl'
sys/syscalls.o:(.data+0xc8): undefined reference to `semop'
sys/sem.o: In function `create':
/home/windea/workshop/ricm4/as/nanvix/src/kernel/sys/sem.c:12: undefined reference to `semget'
/home/windea/workshop/ricm4/as/nanvix/src/kernel/sys/sem.c:17: undefined reference to `semctl'
sys/sem.o: In function `down':
/home/windea/workshop/ricm4/as/nanvix/src/kernel/sys/sem.c:25: undefined reference to `semop'
sys/sem.o: In function `up':
/home/windea/workshop/ricm4/as/nanvix/src/kernel/sys/sem.c:33: undefined reference to `semop'
sys/sem.o: In function `destroy':
/home/windea/workshop/ricm4/as/nanvix/src/kernel/sys/sem.c:41: undefined reference to `semctl'
makefile:67: recipe for target 'all' failed
make[2]: *** [all] Error 1
And finally, the last command line executed by make before the error was:
i386-elf-ld -T arch/x86/link.ld arch/x86/utilities.o arch/x86/io.o arch/x86/boot.o arch/x86/hooks.o arch/x86/setup.o arch/x86/hwint.o arch/x86/8259.o arch/x86/exception.o arch/x86/clock.o arch/x86/hal.o dev/dev.o dev/ata/ata.o dev/klog/klog.o dev/ramdisk/ramdisk.o dev/tty/console.o dev/tty/keyboard.o dev/tty/tty.o fs/file.o fs/block.o fs/super.o fs/buffer.o fs/pipe.o fs/inode.o fs/fs.o init/main.o lib/kstrncpy.o lib/kpanic.o lib/kprintf.o lib/kvsprintf.o lib/krand.o lib/kmemcpy.o lib/ksrand.o lib/kmemdump.o lib/kstrlen.o lib/kstrcmp.o lib/kstrcpy.o lib/kmemset.o lib/kstrncmp.o lib/bitmap.o mm/mm.o mm/paging.o mm/region.o pm/die.o pm/sleep.o pm/pm.o pm/sched.o pm/signal.o sys/times.o sys/stat.o sys/setgid.o sys/alarm.o sys/shutdown.o sys/kill.o sys/chmod.o sys/ioctl.o sys/umask.o sys/close.o sys/_exit.o sys/ustat.o sys/setegid.o sys/getgid.o sys/fork.o sys/getpgrp.o sys/nice.o sys/chroot.o sys/brk.o sys/syscalls.o sys/ps.o sys/wait.o sys/sync.o sys/unlink.o sys/setpgrp.o sys/signal.o sys/pause.o sys/link.o sys/read.o sys/gticks.o sys/fcntl.o sys/utime.o sys/write.o sys/geteuid.o sys/chdir.o sys/pipe.o sys/getegid.o sys/setuid.o sys/access.o sys/execve.o sys/getppid.o sys/chown.o sys/uname.o sys/lseek.o sys/sem.o sys/open.o sys/seteuid.o sys/getuid.o sys/getpid.o -o /home/windea/workshop/ricm4/as/nanvix/bin/kernel
I have no idea if this will help anyone to understand my issue, but now I think you can have a better grasp of what's going on at least.
Looks like you are compiling only the main.c and not fun1.c, fun2.c and fun3.c
You can try to compile as follows:
gcc -c main.c -o main.o
gcc -c fun1.c -o fun1.o
gcc -c fun2.c -o fun2.o
gcc -c fun3.c -o fun3.o
gcc main.o fun1.o fun2.o fun3.o -o all.out

C: duplicate symbols for architecture x86_64

I am trying to create a struct in a header file, and initialize a template struct. For some reason, when including the header file in multiple files, it gives me the following error:
gcc foo.c bar.c -o foo -Wall
duplicate symbol _MYFOO in:
/var/folders/s4/zyw5lgk92wj9ljnsypgwdccr0000gn/T/foo-52f8fc.o
/var/folders/s4/zyw5lgk92wj9ljnsypgwdccr0000gn/T/bar-6dc21f.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
These are my files:
Bar.c:
#include "bar.h"
#include <stdio.h>
void helloWorld() {
printf("Hello world\n");
}
Bar.h
typedef struct Foo Foo;
struct Foo {
int number;
} MYFOO = {2};
void helloWorld(void);
Foo.c
#include "bar.h"
int main() {
helloWorld();
}
Interestingly enough, when I remove the line containing
MYFOO = {2};
The code compiles and works perfectly fine. I believe it has to do with including Bar.h twice, which ends up including that struct twice? But how would I avoid something like that?
Thank you!
You could add a directive to the Bar.h file to check if the file has already been included:
#ifndef _BAR_H_INCLUDED_
// Bar.h not included - declare your structs, etc, here.
// Define _BAR_H_INCLUDED_ to indicate this file has already
// been included
#define _BAR_H_INCLUDED_ 1
#endif
This should at least prevent you including Bar.h multiple times.
EDIT
A better solution might be to include the Bar.c from within the Bar.h:
// Bar.h
#ifndef _BAR_C_INCLUDED_
// code here
// Include Bar.c
#include "Bar.c"
#define _BAR_C_INCLUDED_
#endif
You can then simply include Bar.h in your Foo.c:
// Foo.c
#include <stdio.h>
#include <stdlib.h>
#include "Bar.h"
int main() {
//...
Then to compile:
gcc Foo.c -o Foo
So - here is your updated code - first, Bar.h
#ifndef _BAR_C_INCLUDED_
typedef struct Foo Foo;
struct Foo {
int number;
} MYFOO = {2};
void helloWorld (void);
#include "Bar.c"
#define _BAR_C_INCLUDED_
#endif
Now Bar.c:
void helloWorld() {
printf("Hello world\n");
}
Lastly, Foo.c - include stdio.h here as well as Bar.h (which will, in turn, include Bar.c for us):
#include <stdio.h>
#include "bar.h"
int main() {
helloWorld();
}
And to compile:
gcc Foo.c -o Foo -Wall
After toying around some more, I found the reason for the error coming from the line MYFOO = {2};
It had to do with the fact that I was initializing the struct in my header file.
Header files are meant for definitions, not initializations.
Instead, the solution for the problem was to simply define and initialize the line in the corresponding source file Foo.c.
Now, in that file I included as a global variable:
Foo MYFOO = {2};
Now to access this variable in any other file, such as in my Bar.c, all I needed to do was include the line,
extern Foo MYFOO;
This solved my problem for compilation and meant that I could use the struct in other files as desired!

function runs though header is not included

consider the following code, which causes a weird behavior:
foo.h
#ifndef FOO_H
#define FOO_H
void foo();
#endif
foo.c
#include <stdio.h>
// NOTICE - foo.h is not included!
void foo()
{
printf("foo!\n");
}
main.c
#include "foo.h"
int main()
{
foo();
return 0;
}
running this code I get in the console: foo!
what bugs me here is that I expected that main.c would not be familiar with the implementation of foo(), since foo.h is not included in foo.c, and hence foo() should be an inner function in foo.c. It happened to me both when I ran it in VS2010 and when I compiled an exe using gcc (on windows).
can someone explain this phenomenon? I thought about it and I have no idea why it happens. thanks.
The header file is declaring the function, so when compiling main.c the compiler knows the function signature to validate against. When compiling foo.c, it doesn't need to be declared, as it is the declaration of the function. It is up to the linker to see if there are any unresolved symbols, which there aren't in this case, so all is good, and also why you're seeing this work.
What will happen if there was another function(test.c) included in the above question.
foo.h
#ifndef FOO_H
#define FOO_H
void foo();
#endif
foo.c
#include <stdio.h>
// NOTICE - foo.h is not included!
void foo()
{
printf("foo!\n");
}
test.c
#include <stdio.h>
void foo()
{
printf("foo!\n");
}
main.c
#include "foo.h"
int main()
{
foo();
return 0;
}

visual studio c linker wrap option?

From this article Unit testing with mock objects in C:
This is done by using the --wrap linker option which takes the name of the wrapped function as an argument. If the test was compiled using gcc, the invocation might look like:
$ gcc -g -Wl,--wrap=chef_cook waiter_test.c chef.c
How can I do this when compiling a C project in visual studio?
The --wrap in ld can be emulated by the /ALTERNATENAME option in MSVC Linker.
We start from two compilation units, say foo.o compiled from foo.c, whose external functions are declared in foo.h, and main.o from main.c.
(If foo has been compiled as a library, things won't change much.)
// foo.h
int foo();
// foo.c
int foo() {
return 0;
}
// main.c
#include <stdio.h>
#include "foo.h"
int main() {
int x = foo();
printf("%s\n", x ? "wrapped" : "original");
}
The return value of int foo() is 0, so the snippet of code above will output "original".
Now we override the actual implementation by an alias: The #include "foo.h" in main.c is replaced by
#define foo real_foo
#include "foo.h"
#undef foo
#pragma comment(linker, "/alternatename:real_foo=foo")
Let me explain what happens here:
by #define foo real_foo, the function declaration in foo.h is modified as int real_foo().
However, the symbol in foo.o is still named after int foo(), instead of the alias int real_foo(). That's why we need the /alternatename linker switch.
"/alternatename:real_foo=foo" tells the linker that, if you cannot find the symbol called real_foo, try foo again before throwing an error.
Apparently there is no definition of int real_foo(). MSVC Linker will search for int foo() and link it instead at each occurrence of int real_foo().
As the previous implementation has been aliased, now we redirect int foo() to our new implementation by a macro:
int wrap_foo() {
return real_foo() + 1;
}
#define foo wrap_foo
And we are done here. At last the main.cpp looks like:
#include <stdio.h>
#define foo real_foo
#include "foo.h"
#undef foo
#pragma comment(linker, "/alternatename:real_foo=foo")
int wrap_foo() {
return real_foo() + 1;
}
#define foo wrap_foo
int main() {
int x = foo();
printf("%s\n", x ? "wrapped" : "original");
}
Built in MSVC, it will output "wrapped".

Error while referencing into a global variable using multiple files

These are my code files:
header.h
#ifndef HEADER_H
#define HEADER_H
extern int bar;
#endif
foo.c
#include <stdio.h>
#include "header.h"
void foo(void) {
printf("foo: bar = %d\n", bar);
printf("foo: ++bar = %d\n", ++bar);
}
main.c
#include <stdio.h>
#include "header.h"
int main(void) {
int bar=0;
printf("main: bar = %d\n", bar);
printf("main: ++bar = %d\n", bar);
foo();
return 0;
}
When I try to compile those in Ubuntu:
gcc -c foo.c
gcc main.c foo.o -o program
I get this error from the linker:
/tmp/ccWHhwtm.o: In function `foo':
foo.c:(.text+0x6): undefined reference to `bar'
foo.c:(.text+0x1d): undefined reference to `bar'
foo.c:(.text+0x26): undefined reference to `bar'
foo.c:(.text+0x2c): undefined reference to `bar'
collect2: error: ld returned 1 exit status
As I have seen from other answered questions here, in order to share a global variable to multiple files, you will just have to declare the variable in the header file using extern keyword and define it in one of the .c codes.
That is what I have done here, but I get this error.
What is happening ?
bar should be defined in file scope:
#include <stdio.h>
#include "header.h"
int bar=0;
int main(void) {
....
When I was typing: "What is happening", just then, ironically, I figured out the answer :-P.
The problem is that I define the variable inside main function. Thus the definition scope is limited between the braces.

Resources