Mateus Pires Mateus Pires - 3 months ago 12
C Question

Multiple definition of const variables at header file

I defined some constants in flag.h so link.c and linkedlist.h can use it.
But when I compile with:


clang -Wall main.c link.c linkedlist.c


I get the following


/tmp/linkedlist-o2mcAI.o:(.rodata+0x0): multiple definition of `VARIABLE_NAME'

/tmp/link-oXhyfE.o:(.rodata+0x0): first defined here


for all variables from flag.h used in link.c and linkedlist.c, and at the end:


clang: error: linker command failed with exit code 1 (use -v to see invocation)





A example code of main.c, flag.h, link.h, link.c, linkedlist.h and linkedlist.c:

main.c



#include <stdio.h>
#include "linkedlist.h"

int main(void) {
LinkedList* list = LinkedList_new();
}


flag.h



#ifndef FLAG_H_
#define FLAG_H_

#include <limits.h>

#define FALSE 0
#define TRUE 1

const int OK = 1;
const int ERROR = -1;
const int FLAG = 0;

// other constants

#endif


link.h



#ifndef LINK_H_
#define LINK_H_

typedef struct Link {
int value;
struct Link* next;
} Link;

Link* Link_new(int value);

int useExample(int value);

// other methods

#endif


link.c



#include <stdio.h>
#include <stdlib.h>

#include "link.h"
#include "flag.h"

Link* Link_new(int value)
{
Link* link = malloc(sizeof(Link));
link->value = value;
link->next = NULL;
return link;
}

useExample(int value)
{
if (value == 0) {
return OK; // defined in flag.h
} else {
return FLAG; // defined in flag.h
}
}

// other methods


linkedlist.h



#ifndef LINKEDLIST_H_
#define LINKEDLIST_H_

#include "link.h"

typedef struct LinkedList {
Link* first;
unsigned int size;
} LinkedList;

LinkedList* LinkedList_new();

int anotherUseExample(int value);

// other methods

#endif


linkedlist.c



#include <stdio.h>
#include <stdlib.h>

#include "linkedlist.h"
#include "flag.h"

LinkedList* LinkedList_new() {
LinkedList* list = malloc(sizeof(LinkedList));
list->first = NULL;
list->size = 0;
return list;
}

anotherUseExample(int value)
{
if (value == 0) {
return FLAG; // defined in flag.h
} else {
return ERROR; // defined in flag.h
}
}

// other methods





So how can I use flag.h in link.c and linkedlist.c without occur multiple definition?

And...
The way I'm coding header files and compiling is correct?




The complete output with
-v
:

clang version 3.3 (tags/RELEASE_33/rc3)
Target: i386-redhat-linux-gnu
Thread model: posix
"/usr/bin/clang" -cc1 -triple i386-redhat-linux-gnu -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -main-file-name main.c -mrelocation-model static -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -fuse-init-array -target-cpu pentium4 -target-linker-version 2.23.52.0.1 -v -resource-dir /usr/bin/../lib/clang/3.3 -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/clang/3.3/include -internal-externc-isystem /usr/include -internal-externc-isystem /usr/lib/gcc/i686-redhat-linux/4.8.1/include -Wall -fdebug-compilation-dir /home/jharvard/Desktop/Code/LinkedList -ferror-limit 19 -fmessage-length 80 -mstackrealign -fobjc-runtime=gcc -fobjc-default-synthesize-properties -fdiagnostics-show-option -fcolor-diagnostics -backend-option -vectorize-loops -o /tmp/main-JmZTmN.o -x c main.c
clang -cc1 version 3.3 based upon LLVM 3.3 default target i386-redhat-linux-gnu
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/usr/bin/../lib/clang/3.3/include
/usr/include
/usr/lib/gcc/i686-redhat-linux/4.8.1/include
End of search list.
"/usr/bin/clang" -cc1 -triple i386-redhat-linux-gnu -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -main-file-name link.c -mrelocation-model static -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -fuse-init-array -target-cpu pentium4 -target-linker-version 2.23.52.0.1 -v -resource-dir /usr/bin/../lib/clang/3.3 -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/clang/3.3/include -internal-externc-isystem /usr/include -internal-externc-isystem /usr/lib/gcc/i686-redhat-linux/4.8.1/include -Wall -fdebug-compilation-dir /home/jharvard/Desktop/Code/LinkedList -ferror-limit 19 -fmessage-length 80 -mstackrealign -fobjc-runtime=gcc -fobjc-default-synthesize-properties -fdiagnostics-show-option -fcolor-diagnostics -backend-option -vectorize-loops -o /tmp/link-FtygcZ.o -x c link.c
clang -cc1 version 3.3 based upon LLVM 3.3 default target i386-redhat-linux-gnu
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/usr/bin/../lib/clang/3.3/include
/usr/include
/usr/lib/gcc/i686-redhat-linux/4.8.1/include
End of search list.
"/usr/bin/clang" -cc1 -triple i386-redhat-linux-gnu -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -main-file-name linkedlist.c -mrelocation-model static -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -fuse-init-array -target-cpu pentium4 -target-linker-version 2.23.52.0.1 -v -resource-dir /usr/bin/../lib/clang/3.3 -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/clang/3.3/include -internal-externc-isystem /usr/include -internal-externc-isystem /usr/lib/gcc/i686-redhat-linux/4.8.1/include -Wall -fdebug-compilation-dir /home/jharvard/Desktop/Code/LinkedList -ferror-limit 19 -fmessage-length 80 -mstackrealign -fobjc-runtime=gcc -fobjc-default-synthesize-properties -fdiagnostics-show-option -fcolor-diagnostics -backend-option -vectorize-loops -o /tmp/linkedlist-n0zF1a.o -x c linkedlist.c
clang -cc1 version 3.3 based upon LLVM 3.3 default target i386-redhat-linux-gnu
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/usr/bin/../lib/clang/3.3/include
/usr/include
/usr/lib/gcc/i686-redhat-linux/4.8.1/include
End of search list.
"/usr/bin/ld" --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o a.out /usr/lib/gcc/i686-redhat-linux/4.8.1/../../../crt1.o /usr/lib/gcc/i686-redhat-linux/4.8.1/../../../crti.o /usr/lib/gcc/i686-redhat-linux/4.8.1/crtbegin.o -L/usr/lib/gcc/i686-redhat-linux/4.8.1 -L/usr/lib/gcc/i686-redhat-linux/4.8.1/../../.. -L/lib -L/usr/lib /tmp/main-JmZTmN.o /tmp/link-FtygcZ.o /tmp/linkedlist-n0zF1a.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i686-redhat-linux/4.8.1/crtend.o /usr/lib/gcc/i686-redhat-linux/4.8.1/../../../crtn.o
/tmp/linkedlist-n0zF1a.o:(.rodata+0x4): multiple definition of `ERROR_indexOutOfBounds'
/tmp/link-FtygcZ.o:(.rodata+0x4): first defined here
/tmp/linkedlist-n0zF1a.o:(.rodata+0x8): multiple definition of `ERROR_invalidArgument'
/tmp/link-FtygcZ.o:(.rodata+0x8): first defined here
/tmp/linkedlist-n0zF1a.o:(.rodata+0x10): multiple definition of `FLAG_notFound'
/tmp/link-FtygcZ.o:(.rodata+0x10): first defined here
/tmp/linkedlist-n0zF1a.o:(.rodata+0xc): multiple definition of `FLAG_undefined'
/tmp/link-FtygcZ.o:(.rodata+0xc): first defined here
/tmp/linkedlist-n0zF1a.o:(.rodata+0x0): multiple definition of `OK'
/tmp/link-FtygcZ.o:(.rodata+0x0): first defined here
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Answer

The #include directive in C simply copies the text from the header file. That means that when you compile both link.c and linkedlist.c, the constant definitions from flag.h gets copied into both, and all these constants are now defined in both link.o and linkedlist.o`. When you link the program you get a name you get a multiple definition error.

You need to split the declaration from the definition, and create a flag.c file where you define const int OK = 1; etc., and at flag.h you'll stay with const int OK; etc. That way, the constants will be compiled into a single object file - flag.o - and you won't get a multiple definition error when you link.

Comments