头文件中const变量的多重定义

时间:2021-08-18 15:05:42

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

我在标志中定义了一些常数。h所以链接。c和链表。可以使用它。但当我编译时:

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

铿锵声- wall主要。c链接。c linkedlist.c

I get the following

我得到以下

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

/tmp/linkedlist-o2mcAI.o:(.rodata+0x0):“VARIABLE_NAME”的多重定义

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

/ tmp / link-oXhyfE.o:(.rodata + 0 x0):首先定义

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

对于所有来自标志的变量。h用于链接。c和链表。c,最后:

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

clang: error:退出码1的链接器命令失败(使用-v查看调用)


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

main的示例代码。c,国旗。h,链接。h,链接。c、linkedlist。h和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?

如何使用标志。h的链接。c和链表。c没有出现多重定义?

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

和…我编码头文件和编译的方式是正确的吗?


The complete output with -v:

带-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)

4 个解决方案

#1


9  

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.

C中的#include指令只是从头文件中复制文本。这意味着当你编译两个链接时。c和链表。c,标志中的常数定义。h被复制到两者中,所有这些常数现在都在两个链接中定义。o和linkedlist.o”。当你链接程序时你会得到一个名字你会得到一个多重定义错误。

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.

您需要将声明与定义分离,并创建一个标志。c文件,定义const int OK = 1;等等,在国旗。你会和const int保持一致;这样,常量将被编译成一个对象文件标记。o -当你链接时,你不会得到多重定义错误。

#2


6  

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.

这些都是int类型的,不会产生多个符号错误。它们的优点是可以保留在.h文件中。因此,所有使用它们的函数都是可见的,可以更好地进行优化。

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

正如上面的例子所示,值不必按顺序出现,相同的值可能会出现好几次。

#3


3  

flag.h:

flag.h:

extern const int OK, ERROR, FLAG;

flag.c:

flag.c:

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

#4


0  

@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.

@Idan Arye和@Jens Gustedt给出了两个解决方案。两者都有优点和缺点。enum的一个主要优点是,我们不需要为元素赋值,编译器将自动赋值。复制条目的机会更少,我们可以安全地添加或删除新元素。

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.

enum的缺点是默认为int型。如果我们需要在内存受限的系统(如嵌入式编程)中使用uint8_t,我们可能会遇到问题。但是有些编译器支持-fshort-enums编译器选项,该选项允许编译器将枚举类型的大小设置为最小的数据类型,该类型可以保存所有枚举器值。但我们必须明确地设置这些选项。

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

此外,在C语言中也不可能对枚举类型的变量进行正向声明

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

在头文件和源文件中使用const,我们同样需要将所有的const复制到两个文件中。

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.

const的另一个主要缺点是它们不能用于初始化静态或全局变量。它们不被视为编译时常量,而是被视为只读变量。

#1


9  

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.

C中的#include指令只是从头文件中复制文本。这意味着当你编译两个链接时。c和链表。c,标志中的常数定义。h被复制到两者中,所有这些常数现在都在两个链接中定义。o和linkedlist.o”。当你链接程序时你会得到一个名字你会得到一个多重定义错误。

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.

您需要将声明与定义分离,并创建一个标志。c文件,定义const int OK = 1;等等,在国旗。你会和const int保持一致;这样,常量将被编译成一个对象文件标记。o -当你链接时,你不会得到多重定义错误。

#2


6  

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.

这些都是int类型的,不会产生多个符号错误。它们的优点是可以保留在.h文件中。因此,所有使用它们的函数都是可见的,可以更好地进行优化。

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

正如上面的例子所示,值不必按顺序出现,相同的值可能会出现好几次。

#3


3  

flag.h:

flag.h:

extern const int OK, ERROR, FLAG;

flag.c:

flag.c:

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

#4


0  

@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.

@Idan Arye和@Jens Gustedt给出了两个解决方案。两者都有优点和缺点。enum的一个主要优点是,我们不需要为元素赋值,编译器将自动赋值。复制条目的机会更少,我们可以安全地添加或删除新元素。

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.

enum的缺点是默认为int型。如果我们需要在内存受限的系统(如嵌入式编程)中使用uint8_t,我们可能会遇到问题。但是有些编译器支持-fshort-enums编译器选项,该选项允许编译器将枚举类型的大小设置为最小的数据类型,该类型可以保存所有枚举器值。但我们必须明确地设置这些选项。

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

此外,在C语言中也不可能对枚举类型的变量进行正向声明

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

在头文件和源文件中使用const,我们同样需要将所有的const复制到两个文件中。

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.

const的另一个主要缺点是它们不能用于初始化静态或全局变量。它们不被视为编译时常量,而是被视为只读变量。