为什么我不能在头文件中声明和分配全局变量,即使使用#ifndef HEADER_H也是如此

Som*_*ing 4 c gcc

我看到了一些类似的问题,但在其中没有一个,#ifndef HEADER_H提到了.

我有一个头文件和2个C文件: constants.h main.c mylib.c

constants.h中:

#ifndef CONSTANTS_H
#define CONSTANTS_H

const int NUM_OF_ITEMS = 22;

#endif
Run Code Online (Sandbox Code Playgroud)

mylib.c中:

#include "constants.h"
... code ...
Run Code Online (Sandbox Code Playgroud)

main.c中:

#include "constants.h"

int main() {
    ... code ...
}
Run Code Online (Sandbox Code Playgroud)

当我使用命令编译时:gcc main.c mylib.c -o main,我收到以下错误:

/tmp/ccl55fv3.o:(.rodata+0x0): multiple definition of `NUM_OF_ITEMS'
/tmp/ccyZhu6F.o:(.rodata+0x0): first defined here
collect2: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)
  • 我提到过#ifndef,为什么会这样?
  • 除了将它拆分constants.h为声明和constants.c作业外,还有什么可做的吗?

Dav*_*nan 6

包含头文件的每个转换单元(读取.c源文件)都会生成全局变量的新定义.这就是链接器对有多个定义的原因.请记住,#include执行包含文件的文本插入.从编译器的角度来看,每个翻译单元都包含不同的定义NUM_OF_ITEMS.

您需要在一个翻译单元中定义它.您可以考虑添加一个constants.c包含定义的NUM_OF_ITEMS,并在头文件中只留下一个声明.

或者你可以使用宏:

#define NUM_OF_ITEMS 22
Run Code Online (Sandbox Code Playgroud)

或者正如Jens在下面的评论中建议的那样,枚举常数.

或者你自己建议,通过static链接使对象在每个翻译单元内部.

  • `static`将是一个合理的选择 (2认同)

Cli*_*ord 5

需要包含防护来防止编译期间单个翻译单元的多重包含。另一方面,您遇到的错误是链接器错误 - 因为您有多个包含相同定义的翻译单元(目标文件)。

在 C 中,通常将#define常量定义为宏。这在类型安全方面有缺点。或者,您可以做一到两件事:

  1. 通过声明来本地化每个翻译单元中的常量static

    static const int NUM_OF_ITEMS = 22;
    
    Run Code Online (Sandbox Code Playgroud)
  2. 声明它extern,然后在单个翻译单元中定义:

     extern const int NUM_OF_ITEMS ;
    
    Run Code Online (Sandbox Code Playgroud)

    常量.c:

    #include constants .h
    const int NUM_OF_ITEMS = 22;
    
    Run Code Online (Sandbox Code Playgroud)

选项 1 是 C++ 中的常见做法,其中 的语义const与 C 有所不同,或者至少定义更清晰,并且除非引用或指针指向常量,否则常量将被插入到代码中,就好像是宏一样- 即“变量”不会有明显的存储。在 C 代码中,这可能会发生,也可能不会发生,但无论如何它都会工作,但效率可能会稍低。