Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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)
like image 415
Mateus Pires Avatar asked Jun 14 '14 02:06

Mateus Pires


People also ask

Do constants go in header files?

Note that the constants are declared/defined in only a single header file that gets included in multiple source files.

Should constants be in header or source?

For this reason, constexpr variables cannot be separated into header and source file, they have to be defined in the header file. Given the above downsides, prefer defining your constants in the header file.

Is it necessary to initialize const variables?

A constant variable is one whose value cannot be updated or altered anywhere in your program. A constant variable must be initialized at its declaration.

What is the const variable?

The const keyword specifies that a variable's value is constant and tells the compiler to prevent the programmer from modifying it.


4 Answers

flag.h:

extern const int OK, ERROR, FLAG;

flag.c:

const int OK = 1;
const int ERROR = -1;
const int FLAG = 0;
like image 166
BLUEPIXY Avatar answered Oct 18 '22 04:10

BLUEPIXY


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.

like image 24
Idan Arye Avatar answered Oct 18 '22 03:10

Idan Arye


@Idan Arye and @Jens Gustedt gave two solutions. Both have advantages and disadvantages. One main advantage with enum is that we need not assign any values to elements and compiler will automatically assign values. There is less chance for duplicate entries and we can add or remove new elements safely.

Disadvantage with enum is that it is int by default. If we need uint8_t in memory constrained systems like embedded programming, we may face problems. But some compilers support -fshort-enums compiler option which allows the compiler to set the size of an enumeration type to the smallest data type that can hold all enumerator values. But we have to set these options specifically.

Also Forward declaration of enumerated type of variable is not possible in C

With const usage in header file and in source file, again we need to copy all consts to both the files.

Also values may get duplicated (Dangerous in case values have to be unique).

Another main disadvantage with const is that they cannot be used for initializing static or global variables. They are not treated as compile time constants instead they are treated as read-only variables.

like image 34
Rajesh Avatar answered Oct 18 '22 02:10

Rajesh


Since you don't need these constants as objects, you should just use a different feature to define them, enumerations.

enum { OK = 1, ERROR = -1, FLAG = 0, ONE = 1, };

These are of type int and will never give rise to multiple symbol errors. Their advantage is that they can remain inside the .h file. Thereby there value is visible to all functions that use them and can better be optimized.

As can be seen in the example above, values don't have to appear in order and the same value may appear several times.

like image 34
Jens Gustedt Avatar answered Oct 18 '22 04:10

Jens Gustedt