[英]#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.cpp
: error: 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.