为什么我的 #ifndef 预处理器指令在编译时不能阻止 header 的多次包含?
Why doesn't my #ifndef preprocessor instruction prevent multiple inclusions of a header when compiling?
编辑:解决了。感谢@Govind-Pramar 和@SomeWittyUsername 提供解决方案,在 header 中将常量声明为 extern 并在 C 文件中初始化它们。
我正在做这个项目:https://github.com/SuperTotoGo/AES_Cipher
并且我有一个header文件,其中包含需要被项目的其他模块访问的常量(所有错误都与"aes_const.h"中定义的常量有关),所以是包含在所有所述模块中。
为了避免多重包含,我使用了#ifndef/#define 预处理器指令,但是在编译时出现了这个错误:
gcc -std=c99 -o aes.out aes_ciph_func.c aes_kexp_func.c aes_math.c main.c
usr/bin/ld: /tmp/cc9HKLA4.o:(.rodata+0x0): multiple definition of `AES_SUB_BOX'; /tmp/ccC4gp1r.o:(.rodata+0x0): first defined here
/usr/bin/ld: /tmp/cc9HKLA4.o:(.rodata+0x100): multiple definition of `INV_AES_SUB_BOX'; /tmp/ccC4gp1r.o:(.rodata+0x100): first defined here
/usr/bin/ld: /tmp/cc9HKLA4.o:(.rodata+0x200): multiple definition of `AES_LOG_TABLE'; /tmp/ccC4gp1r.o:(.rodata+0x200): first defined here
/usr/bin/ld: /tmp/cc9HKLA4.o:(.rodata+0x300): multiple definition of `AES_ALOG_TABLE'; /tmp/ccC4gp1r.o:(.rodata+0x300): first defined here
/usr/bin/ld: /tmp/cc9HKLA4.o:(.rodata+0x400): multiple definition of `AES_MULT_MAT'; /tmp/ccC4gp1r.o:(.rodata+0x400): first defined here
/usr/bin/ld: /tmp/cc9HKLA4.o:(.rodata+0x410): multiple definition of `INV_AES_MULT_MAT'; /tmp/ccC4gp1r.o:(.rodata+0x410): first defined here
/usr/bin/ld: /tmp/cc9HKLA4.o:(.rodata+0x420): multiple definition of `RCON'; /tmp/ccC4gp1r.o:(.rodata+0x420): first defined here
/usr/bin/ld: /tmp/ccGpzVgH.o:(.rodata+0x0): multiple definition of `AES_SUB_BOX'; /tmp/ccC4gp1r.o:(.rodata+0x0): first defined here
/usr/bin/ld: /tmp/ccGpzVgH.o:(.rodata+0x100): multiple definition of `INV_AES_SUB_BOX'; /tmp/ccC4gp1r.o:(.rodata+0x100): first defined here
/usr/bin/ld: /tmp/ccGpzVgH.o:(.rodata+0x200): multiple definition of `AES_LOG_TABLE'; /tmp/ccC4gp1r.o:(.rodata+0x200): first defined here
/usr/bin/ld: /tmp/ccGpzVgH.o:(.rodata+0x300): multiple definition of `AES_ALOG_TABLE'; /tmp/ccC4gp1r.o:(.rodata+0x300): first defined here
/usr/bin/ld: /tmp/ccGpzVgH.o:(.rodata+0x400): multiple definition of `AES_MULT_MAT'; /tmp/ccC4gp1r.o:(.rodata+0x400): first defined here
/usr/bin/ld: /tmp/ccGpzVgH.o:(.rodata+0x410): multiple definition of `INV_AES_MULT_MAT'; /tmp/ccC4gp1r.o:(.rodata+0x410): first defined here
/usr/bin/ld: /tmp/ccGpzVgH.o:(.rodata+0x420): multiple definition of `RCON'; /tmp/ccC4gp1r.o:(.rodata+0x420): first defined here
/usr/bin/ld: /tmp/ccZWo13j.o:(.rodata+0x0): multiple definition of `AES_SUB_BOX'; /tmp/ccC4gp1r.o:(.rodata+0x0): first defined here
/usr/bin/ld: /tmp/ccZWo13j.o:(.rodata+0x100): multiple definition of `INV_AES_SUB_BOX'; /tmp/ccC4gp1r.o:(.rodata+0x100): first defined here
/usr/bin/ld: /tmp/ccZWo13j.o:(.rodata+0x200): multiple definition of `AES_LOG_TABLE'; /tmp/ccC4gp1r.o:(.rodata+0x200): first defined here
/usr/bin/ld: /tmp/ccZWo13j.o:(.rodata+0x300): multiple definition of `AES_ALOG_TABLE'; /tmp/ccC4gp1r.o:(.rodata+0x300): first defined here
/usr/bin/ld: /tmp/ccZWo13j.o:(.rodata+0x400): multiple definition of `AES_MULT_MAT'; /tmp/ccC4gp1r.o:(.rodata+0x400): first defined here
/usr/bin/ld: /tmp/ccZWo13j.o:(.rodata+0x410): multiple definition of `INV_AES_MULT_MAT'; /tmp/ccC4gp1r.o:(.rodata+0x410): first defined here
/usr/bin/ld: /tmp/ccZWo13j.o:(.rodata+0x420): multiple definition of `RCON'; /tmp/ccC4gp1r.o:(.rodata+0x420): first defined here
collect2: error: ld returned 1 exit status
如果我的理解没有错的话,是我的header被多次收录造成的。
aes_const.h 看起来像这样:
#include <stdint.h>
#ifndef AES_CONST_H
#define AES_CONST_H
//CONSTANTS ARE DECLARED HERE
#endif
我的模块基本上是这样的:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include "aes_kexp_func.h"
#include "aes_const.h"
//FUNCTIONS ARE IMPLEMENTED HERE
包含模块函数原型的header:
#ifndef MODULE_NAME_H
#define MODULE_NAME_H
//FUNCTIONS PROTOTYPES ARE HERE
#endif
和我的主文件:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include "aes_const.h"
#include "aes_ctypes.h"
#include "aes_math.h"
#include "aes_ciph_func.h"
#include "aes_kexp_func.h"
main(){/*code here*/}
我的#ifndef 不应该阻止这种情况发生吗?我错过了什么?
#ifndef
是编译时指令。您在链接期间遇到问题。您的每个源文件都是单独编译的,但之后它们会链接在一起。因此,如果您在多个源文件包含的头文件中定义了常量,您将在链接期间发生冲突。头文件的经验法则 - 声明那里的数据但不要定义它。如果你有常量需要被多个模块访问,在一个模块中定义它们并在共享头文件中将它们声明为extern。
Include guards(#ifndef _HEADER_NAME_
和 #pragma once
形式)防止相同的 header 在同一个翻译单元中重复包含,而不是在不同的 TU 中重复包含。
您可以做的是:
用extern
声明替换aes_const.h
中的常量定义,像这样:
extern const uint8_t AES_SUB_BOX[16][16];
在您的任何源文件中,完整定义全局变量:
const uint8_t AES_SUB_BOX[16][16] = { /* your initialization here */ };
你犯了一个简单的错误。您在 .h 文件中声明真实数据和可能的代码。您应该只在 C 文件中执行此操作。在 .h 文件中,所有变量都应声明为 extern,它只发出符号而不是对象本身。
编辑:解决了。感谢@Govind-Pramar 和@SomeWittyUsername 提供解决方案,在 header 中将常量声明为 extern 并在 C 文件中初始化它们。
我正在做这个项目:https://github.com/SuperTotoGo/AES_Cipher
并且我有一个header文件,其中包含需要被项目的其他模块访问的常量(所有错误都与"aes_const.h"中定义的常量有关),所以是包含在所有所述模块中。 为了避免多重包含,我使用了#ifndef/#define 预处理器指令,但是在编译时出现了这个错误:
gcc -std=c99 -o aes.out aes_ciph_func.c aes_kexp_func.c aes_math.c main.c
usr/bin/ld: /tmp/cc9HKLA4.o:(.rodata+0x0): multiple definition of `AES_SUB_BOX'; /tmp/ccC4gp1r.o:(.rodata+0x0): first defined here
/usr/bin/ld: /tmp/cc9HKLA4.o:(.rodata+0x100): multiple definition of `INV_AES_SUB_BOX'; /tmp/ccC4gp1r.o:(.rodata+0x100): first defined here
/usr/bin/ld: /tmp/cc9HKLA4.o:(.rodata+0x200): multiple definition of `AES_LOG_TABLE'; /tmp/ccC4gp1r.o:(.rodata+0x200): first defined here
/usr/bin/ld: /tmp/cc9HKLA4.o:(.rodata+0x300): multiple definition of `AES_ALOG_TABLE'; /tmp/ccC4gp1r.o:(.rodata+0x300): first defined here
/usr/bin/ld: /tmp/cc9HKLA4.o:(.rodata+0x400): multiple definition of `AES_MULT_MAT'; /tmp/ccC4gp1r.o:(.rodata+0x400): first defined here
/usr/bin/ld: /tmp/cc9HKLA4.o:(.rodata+0x410): multiple definition of `INV_AES_MULT_MAT'; /tmp/ccC4gp1r.o:(.rodata+0x410): first defined here
/usr/bin/ld: /tmp/cc9HKLA4.o:(.rodata+0x420): multiple definition of `RCON'; /tmp/ccC4gp1r.o:(.rodata+0x420): first defined here
/usr/bin/ld: /tmp/ccGpzVgH.o:(.rodata+0x0): multiple definition of `AES_SUB_BOX'; /tmp/ccC4gp1r.o:(.rodata+0x0): first defined here
/usr/bin/ld: /tmp/ccGpzVgH.o:(.rodata+0x100): multiple definition of `INV_AES_SUB_BOX'; /tmp/ccC4gp1r.o:(.rodata+0x100): first defined here
/usr/bin/ld: /tmp/ccGpzVgH.o:(.rodata+0x200): multiple definition of `AES_LOG_TABLE'; /tmp/ccC4gp1r.o:(.rodata+0x200): first defined here
/usr/bin/ld: /tmp/ccGpzVgH.o:(.rodata+0x300): multiple definition of `AES_ALOG_TABLE'; /tmp/ccC4gp1r.o:(.rodata+0x300): first defined here
/usr/bin/ld: /tmp/ccGpzVgH.o:(.rodata+0x400): multiple definition of `AES_MULT_MAT'; /tmp/ccC4gp1r.o:(.rodata+0x400): first defined here
/usr/bin/ld: /tmp/ccGpzVgH.o:(.rodata+0x410): multiple definition of `INV_AES_MULT_MAT'; /tmp/ccC4gp1r.o:(.rodata+0x410): first defined here
/usr/bin/ld: /tmp/ccGpzVgH.o:(.rodata+0x420): multiple definition of `RCON'; /tmp/ccC4gp1r.o:(.rodata+0x420): first defined here
/usr/bin/ld: /tmp/ccZWo13j.o:(.rodata+0x0): multiple definition of `AES_SUB_BOX'; /tmp/ccC4gp1r.o:(.rodata+0x0): first defined here
/usr/bin/ld: /tmp/ccZWo13j.o:(.rodata+0x100): multiple definition of `INV_AES_SUB_BOX'; /tmp/ccC4gp1r.o:(.rodata+0x100): first defined here
/usr/bin/ld: /tmp/ccZWo13j.o:(.rodata+0x200): multiple definition of `AES_LOG_TABLE'; /tmp/ccC4gp1r.o:(.rodata+0x200): first defined here
/usr/bin/ld: /tmp/ccZWo13j.o:(.rodata+0x300): multiple definition of `AES_ALOG_TABLE'; /tmp/ccC4gp1r.o:(.rodata+0x300): first defined here
/usr/bin/ld: /tmp/ccZWo13j.o:(.rodata+0x400): multiple definition of `AES_MULT_MAT'; /tmp/ccC4gp1r.o:(.rodata+0x400): first defined here
/usr/bin/ld: /tmp/ccZWo13j.o:(.rodata+0x410): multiple definition of `INV_AES_MULT_MAT'; /tmp/ccC4gp1r.o:(.rodata+0x410): first defined here
/usr/bin/ld: /tmp/ccZWo13j.o:(.rodata+0x420): multiple definition of `RCON'; /tmp/ccC4gp1r.o:(.rodata+0x420): first defined here
collect2: error: ld returned 1 exit status
如果我的理解没有错的话,是我的header被多次收录造成的。
aes_const.h 看起来像这样:
#include <stdint.h>
#ifndef AES_CONST_H
#define AES_CONST_H
//CONSTANTS ARE DECLARED HERE
#endif
我的模块基本上是这样的:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include "aes_kexp_func.h"
#include "aes_const.h"
//FUNCTIONS ARE IMPLEMENTED HERE
包含模块函数原型的header:
#ifndef MODULE_NAME_H
#define MODULE_NAME_H
//FUNCTIONS PROTOTYPES ARE HERE
#endif
和我的主文件:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include "aes_const.h"
#include "aes_ctypes.h"
#include "aes_math.h"
#include "aes_ciph_func.h"
#include "aes_kexp_func.h"
main(){/*code here*/}
我的#ifndef 不应该阻止这种情况发生吗?我错过了什么?
#ifndef
是编译时指令。您在链接期间遇到问题。您的每个源文件都是单独编译的,但之后它们会链接在一起。因此,如果您在多个源文件包含的头文件中定义了常量,您将在链接期间发生冲突。头文件的经验法则 - 声明那里的数据但不要定义它。如果你有常量需要被多个模块访问,在一个模块中定义它们并在共享头文件中将它们声明为extern。
Include guards(#ifndef _HEADER_NAME_
和 #pragma once
形式)防止相同的 header 在同一个翻译单元中重复包含,而不是在不同的 TU 中重复包含。
您可以做的是:
用
extern
声明替换aes_const.h
中的常量定义,像这样:extern const uint8_t AES_SUB_BOX[16][16];
在您的任何源文件中,完整定义全局变量:
const uint8_t AES_SUB_BOX[16][16] = { /* your initialization here */ };
你犯了一个简单的错误。您在 .h 文件中声明真实数据和可能的代码。您应该只在 C 文件中执行此操作。在 .h 文件中,所有变量都应声明为 extern,它只发出符号而不是对象本身。