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
Related
I have 3 .c files main.c, fun1.c, fun2.c
char buff[50];//in fun1.c
char *arg; //in fun2.c
arg = strstr(buff, "001"); //in fun2.c
I want to print buff in fun2.c but it gives an error buff undeclared, even though I declared it in fun1.h as extern char buff[];
There are functions in fun1.c and fun2.c each
It is hard to say what is wrong with your particular program, but here is an example which links 2 .c files with one .h file.
1. A header file functions.h:
#include <stdio.h>
extern void func();
Where I use extern to provide definitions for another file.
2. Now, a functions.c file which uses this header file:
#include "functions.h"
void func() {
printf("hello");
}
This needs to #include the header file, and use the function void() to print a message.
3. Finally, a main.c file which links it all together:
#include <stdio.h>
#include <stdlib.h>
#include "functions.h"
int main(void) {
func();
return 0;
}
Which also needs function.h as it uses func(). You then can compile the code as:
gcc -Wall -Wextra -g main.c functions.c -o main
You could also look into makefiles, which would reduce this long compilation line to simply make.
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.
I had created this minimal example to illustrate my problem with extern declaration with Visual Studio 2008 (required to compile a python 2.7 extension). The same example is working well with gcc.
The result is that I have 2 separate global_var variables instead of a unique one in lib.c
the library interface : lib.h
#ifndef LIB_H
#define LIB_H 1
int __declspec( dllexport ) displayGlob();
#endif // LIB_H
the library code
// lib.c
#include<stdio.h>
int global_var=2;
int __declspec( dllexport ) displayGlob() {
printf("lib.c global_var=%d\n", global_var);
return global_var;
}
the user code that uses the library variable "global_var" and function displayGlob()
// main.c
#include"lib.h"
#include<stdio.h>
#include<stdlib.h>
extern int global_var=0; // must be initialized otherwise "error LNK2001: unresolved external symbol global_var"
int main(int argc, char *argv[])
{
printf("main.c global_var=%d\n", global_var);
displayGlob();
global_var = 3;
printf("main.c global_var=%d\n", global_var);
displayGlob();
exit(0);
}
execution result is:
main.c global_var=0
lib.c global_var=2
main.c global_var=3
lib.c global_var=2
Questions:
1 - Why must I initialize the extern variable in lib.h with Visual Studio and not Gcc ?
2 - Why the global_var lib.c displayed by the second displayGlob() is not modified to 3 ?
thanks for any hint !
Laurent
UPDATE: moved extern declaration of global_var from lib.h to main.c (even simpler example)
and of course problems remain...
Because C preprocesor basically pastes the content when you call #include, it the same as you declared your extern inside of main.c file. This means that this symbol is defined twice (in main.c and in lib.c).
What you should do is to add extern declaration to lib.c (for example by including lib.h) and initialize the value there, then remove initialization from lib.h.
So it should be like this:
lib.h:
extern global_var;
lib.c:
#include "lib.h"
int global_var=2;
main.c
#include "lib.h"
(no global_var definition/declaration here)
Solved myself, my fault.
Under Gcc I built both a static library and a dynamic library. My main.c was linked with the STATIC library, so variable resolution between lib.c and main.c was resolved at link time. I forgot that.
Under Visual Studio, I only built a DYNAMIC library, so it was normal variable linkage could not happen between the DLL and main.o
Sorry for any confusion created...
I'm doing a project for school, so I need to compile it with:
gcc hide.c stegano.c -o hide -ansi -pedantic -Wall -Werror
But then I get this errors:
/tmp/ccDME1jC.o: In function `calculate_n':
stegano.c:(.text+0x0): multiple definition of `calculate_n'
/tmp/ccQxPZJu.o:hide.c:(.text+0x0): first defined here
/tmp/ccDME1jC.o: In function `tam_msg':
stegano.c:(.text+0x87): multiple definition of `tam_msg'
/tmp/ccQxPZJu.o:hide.c:(.text+0x87): first defined here
/tmp/ccDME1jC.o: In function `insere_msg':
stegano.c:(.text+0xe1): multiple definition of `insere_msg'
/tmp/ccQxPZJu.o:hide.c:(.text+0xe1): first defined here
/tmp/ccDME1jC.o: In function `copia':
stegano.c:(.text+0x201): multiple definition of `copia'
/tmp/ccQxPZJu.o:hide.c:(.text+0x201): first defined here
/tmp/ccDME1jC.o: In function `esconde_msg':
stegano.c:(.text+0x274): multiple definition of `esconde_msg'
/tmp/ccQxPZJu.o:hide.c:(.text+0x274): first defined here
collect2: ld returned 1 exit status
The program code is like this, I think that the error is probably in the include's so I hid the actual code:
The program hide.c is like this:
#include <stdio.h>
#include <stdlib.h>
#include "stegano.c"
//code//
Then it calls stegano.c, that contains all the actual function used in hide.c:
#include <stdio.h>
#include <stdlib.h>
#include "stegano.h"
//code//
And the header file stegano.h:
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
typedef unsigned char Byte;
void calculate_n(char name[MAX], int* n, int* x);
int tam_msg(char name[MAX]);
void insere_msg(int size, char name[MAX], Byte* v);
void copia(Byte* v1, Byte *v2, int size);
void esconde_msg(Byte* msg, char name1[MAX], char name2[MAX]);
Thanks for helping!
Caused by this:
#include "stegano.c"
this will pull all the function definitions in stegano.c into hide.c. Meaning the stegano.c and hide.c now define the same functions. This will produce the multiple definition errors you see when you attempt to (compile and) link.
Include the header file instead:
#include "stegano.h"
You need to remove the #include "stegano.c". Include the stegano.h file instead.
By including the .c file you basically try to compile the code from that file twice (once when including it and once when compiling the file directly) and thus both stegano.o and hide.o will contain the same functions which will break in the linking phase.
I'm trying to understand how global variables and functions work in C. My program compiles and works fine with gcc, but does not compile with g++. I have the following files:
globals.h:
int i;
void fun();
globals.c:
#include "stdlib.h"
#include "stdio.h"
void fun()
{
printf("global function\n");
}
main.c:
#include "stdlib.h"
#include "stdio.h"
#include "globals.h"
void myfun();
int main()
{
i=1;
myfun();
return 0;
}
And finally, myfun.c:
#include "stdlib.h"
#include "stdio.h"
#include "globals.h"
void myfun()
{
fun();
}
I get the following error when compiling with g++:
/tmp/ccoZxBg9.o:(.bss+0x0): multiple definition of `i'
/tmp/ccz8cPTA.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status
Any ideas why? I would prefer to compile with g++.
Every file you include globals.h from will define "int i".
Instead, put "extern int i;" into the header file and then put the actual definition of "int i = 1;" in globals.c.
Putting header guards around globals.h would be sensible too.
Edit: In answer to your question its because a #include works kind of like a cut and paste. It pastes the contents of the included file into the c file that you are calling include from. As you include "globals.h" from main.c and myfun.c you define int i = 1 in both files. This value, being global, gets put into the table of linkable values. If you have the same variable name twice then the linker won't be able to tell which one it needs and you get the error you are seeing. Instead by adding extern on the front in the header file you are telling each file that "int i" is defined somewhere else. Obviously, you need to define it somewhere else (and ONLY in one place) so defining it in globals.c makes perfect sense.
Hope that helps :)
I would add an include guard in your globals file
#ifndef GLOBALS_H
#define GLOBALS_H
int i;
void fun();
#endif
Edit: Change your globals to be like this (using extern as the other answer describes)
globals.h
extern int i;
extern void fun();
globals.c
#include "stdlib.h"
#include "stdio.h"
int i;
void fun()
{
printf("global function\n");
}
I compiled it with
g++ globals.c main.c myfun.c
and it ran ok
Several things wrong here; several other things highly recommended:
globals.h:
#ifndef GLOBALS_H
#define GLOBALS_H
extern int my_global;
#ifdef __cplusplus
extern "C" {
#endif
void fun();
#ifdef __cplusplus
}
#endif
#endif
/* GLOBALS_H */
globals.c:
#include <stdlib.h>
#include <stdio.h>
#include "globals.h"
int my_global;
void fun()
{
printf("global function: %d\n", my_global);
}
main.c:
#include <stdlib.h>
#include <stdio.h>
#include "globals.h"
void myfun();
int main()
{
my_global=1;
myfun();
return 0;
}
void myfun()
{
fun();
}
You should declare "extern int myvar" in your header, and actually allocate "int myvar" in one and only one .c file.
You should include "globals.h" in every file that uses "myvar" - including the file where it's allocated.
Especially if you're planning on mixing C and C++ modules, you should use 'extern "C"' to distinguish non-C++ functions.
System headers should be "#include <some_header.h>"; your own headers should use quotes (#include "myheader.h") instead.
Short variable names like "i" might be OK for a strictly local variable (like a loop index), but you should always use longer, descriptive names whenever you can't avoid using a global variable.
I added a "printf" for my_global.
'Hope that helps!
I had this problem when porting some old C code to C++. The problem was it was a project that was connected to a database, and i wanted to port the database to c++ but not the rest. The database pulled in some C dependencies that couldn't be ported, so i needed the C code that overlapped both the database and the other project to compile in g++ as well as gcc...
The solution to this problem is to define all variables as extern in the .h file. then when you compile in either gcc or g++ it will report symbols missing in the .c files. So edit the .c files in the error messages and insert the declaration into all the .c files that need the variables. Note: you may have to declare it in multiple .c files, which is what threw me and why I was stuck on this problem for ages.
Anyway this solved my problem and the code compiles cleanly under both gcc and g++ now.