Search code examples
cc-preprocessorlinkage

Why doesn't my #ifndef preprocessor instruction prevent multiple inclusions of a header when compiling?


Edit : Solved it. Thanks to @Govind-Pramar and @SomeWittyUsername for providing the solution, declaring the constant as extern in a header and initializing them in a C file works.

I am working on this project : https://github.com/SuperTotoGo/AES_Cipher

And I have a header file that contains constants (all the errors are related to the constants defined in "aes_const.h") that need to be accessed by other modules of the project, and so is included in all said modules. In order to avoid multiple inclusions I used the #ifndef/#define preprocessor instructions, but when compiling I get this error:

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

Which, if my understanding is right, are caused by my header being included multiple times.

aes_const.h looks like this :

#include <stdint.h>

#ifndef AES_CONST_H
#define AES_CONST_H

//CONSTANTS ARE DECLARED HERE

#endif

my modules look basically like this :

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

#include "aes_kexp_func.h"
#include "aes_const.h"

//FUNCTIONS ARE IMPLEMENTED HERE

the header containing the modules functions prototype :

#ifndef MODULE_NAME_H
#define MODULE_NAME_H

//FUNCTIONS PROTOTYPES ARE HERE

#endif

and my main file :

#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*/}

Shouldn't my #ifndef prevent this from happening? What am I missing?


Solution

  • Include guards (both the #ifndef _HEADER_NAME_ and #pragma once forms) prevent the same header from being included repeatedly within the same translation unit, not from being included repeatedly within different TUs.

    What you can do is:

    1. Replace the constant definitions in aes_const.h with extern declarations, like so:

      extern const uint8_t AES_SUB_BOX[16][16];
      
    2. In any of your source files, define the global variables completely:

      const uint8_t AES_SUB_BOX[16][16] = { /* your initialization here */ };