簡體   English   中英

#include保護功能無效-或我不理解

[英]#include guard doesn't work - or I don't understand it

我使用幾個文件:main.c assembler.c fileHandlers.c handlers.c另外,我還有幾個頭文件,其中包含常量,函數原型等。在其中一個(“ datatypes.h”)中,我定義了一個字符串數組:

#ifndef DATATYPES_H
#define DATATYPES_H
const char *OPCODES = {"str1",..., str15}.
#endif

然后,我將此標頭包含在我的所有文件中(因為它們都在某個時候使用了它)。

這是我的makefile:

main: main.o assembler.o filesHandler.o handlers.o
    gcc -g -Wall -ansi -pedantic main.o assembler.o filesHandler.o handlers.o -o main

main.o: main.c
    gcc -g -c -Wall -ansi -pedantic main.c -o main.o

assembler.o: assembler.c
    gcc -g -c -Wall -ansi -pedantic assembler.c -o assembler.o

filesHandler.o: filesHandler.c
    gcc -g -c -Wall -ansi -pedantic filesHandler.c -o filesHandler.o

handlers.o: handlers.c
    gcc -g -c -Wall -ansi -pedantic handlers.c -o handlers.o

當我嘗試編譯時,出現以下錯誤:

gcc -g -c -Wall -ansi -pedantic assembler.c -o assembler.o
gcc -g -c -Wall -ansi -pedantic filesHandler.c -o filesHandler.o
filesHandler.c: In function ‘readFile’:
filesHandler.c:14:10: warning: unused variable ‘addressing’ [-Wunused-variable]
     char addressing[MAXWORD];
          ^
gcc -g -Wall -ansi -pedantic main.o assembler.o filesHandler.o handlers.o -o main
assembler.o:(.data+0x0): multiple definition of `OPCODES'
main.o:(.data+0x0): first defined here
filesHandler.o:(.data+0x0): multiple definition of `OPCODES'
main.o:(.data+0x0): first defined here
handlers.o:(.data+0x0): multiple definition of `OPCODES'
main.o:(.data+0x0): first defined here
collect2: error: ld returned 1 exit status
make: *** [main] Error 1

現在,我了解到由於某種原因,在預處理之后多次定義了數組,但是我不知道為什么。 我閱讀了有關#include Guards的Wikipedia文章,以及其他更多資源。 他們都指示像我一樣去做,但是那是行不通的。

很抱歉加載這么多數據,但是我希望它可以防止不必要的后續操作。

謝謝,埃拉德

使用適當的include防護(您似乎應該是的,現在您已經更新了問題),頭文件在每個翻譯單元中僅包含一次。

基本上每個.cpp文件都是一個翻譯單元,並將#include的所有頭文件復制到其中。 每個.cpp文件都分別編譯成一個目標文件.o )。

然后將目標文件鏈接到最終二進制文件中。

因此,在每個目標文件中都可以看到每個標頭中的代碼,然后在最終的二進制文件中可以看到多次。 如果只在頭文件中有聲明 ,這很好,例如

const char* opcodes;

每個翻譯單元都知道有一個名為opcodes的字符串,但不會嘗試創建實際的變量。

但是,如果您在頭文件中有定義 ,則會多次看到該定義 ,這是不允許的,並且每個轉換單元都將嘗試創建實際變量:

const char* opcodes = "foobar";

您應該改為將聲明放入頭文件中並使用extern關鍵字,以便每個翻譯單元都可以看到名稱並加以使用,但將定義放入單個.cpp文件中,因此實際上僅創建一次,其他所有人都引用同一個實例。

// foo.h included everywhere
#ifndef FOO_H
#define FOO_H
extern const char* opcodes;
#endif

// foo.cpp
#include "foo.h"
const char* opcodes = "foobar";

工作示例:

// a.h
#ifndef A_H
#define A_H
extern const char* foo;
#endif

// a.cpp
#include "a.h"
const char* foo = "Foo";

// main.cpp
#include <iostream>
#include "a.h"
int main() {
    std::cout << foo << '\n';
}

然后,我在單獨的步驟中進行編譯和鏈接:

$ g++492 --std=c++14 -Wall -W -Werror -c a.cpp -o a.o
$ g++492 --std=c++14 -Wall -W -Werror -c main.cpp -o main.o
$ g++492 --std=c++14 main.o a.o -o main.tsk
$ ./main.tsk 
Foo

刪除extern我可以編譯main.cpp ,但是不能編譯a.cpperror: redefinition of 'const char* foo'

然后,如果我嘗試將新的main.o與舊的a.cpp ,我a.cpp收到並出錯,更像是您的原始內容: multiple definition of 'foo'

那是一個變量定義,它的默認鏈接是外部的。

這意味着您在每個翻譯單元中都有一個帶有外部鏈接的定義,並在其中包含標題。

將標題內容更改為僅包含聲明

extern const char *OPCODES;

並將定義恰好放在一個源文件中,而不是標頭中。

您應該在標頭中聲明OPCODES,並在源文件中對其進行定義。

datatypes.h

const char *OPCODES;

datatypes.c或datatypes.cpp

const char *OPCODES = {"str1",..., str15};

否則將在所有包含.data文件的.o文件中生成“ OPCODES”符號,然后出現鏈接錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM