a.h:
#ifndef _KNIFE_ADT_H
#define _KNIFE_ADT_H
enum Color{red, greed, blue};
typedef struct a{
int a;
double b;
Color c;
}A_type;
A_type A_array[1024];// (1)
int Count;
void func(A_type A, Color color_type)
#endif
a.c:
#include "a.h"
Count = 0;// (2)
void func(A_type A, Color color_type){
;
}
main.c:
#include "a.h"
int main(){
Count = 0;
return 0;
}
问题:
如上文件结构,编译会报重复定义的错误。在VS中,会报错.obj重定义。怎样处理最好?
另外如(2),如果想要给.h文件中变量初始化,最合适的方法是?
补充:
1.将声明写在.C文件中,.h文件中只有enum枚举常量与结构体的声明,所有变量定义放在.c文件中:
c1.h:
#ifndef _KNIFE_ADT_H
#define _KNIFE_ADT_H
enum Color{red, greed, blue};
struct a;
typedef struct a A_type;
void func(A_type A, Color color_type);
#endif
c1.c:
#include "c1.h"
struct a{
int a;
double b;
Color c;
};
A_type A_array[1024];// (1)
int Count;
void func(A_type A, Color color_type){
;
}
main.c:
#include "c1.h"
int main(){
Count = 0;
return 0;
}
VS2012编译信息:
1>c:\test\test_file\c1.cpp(4): error C2380: “a”前的类型(构造函数有返回类型或是当前类型名称的非法重定义?)
1> 正在生成代码...
1> 正在编译...
1> main.cpp
1>c:\test\test_file\main.cpp(4): error C2065: “Count”: 未声明的标识符
在头文件中声明int Count, 即可消除最后一条编译错误信息。
另外,在头文件中声明int Count后又在源文件中加上extern int Count, 有什么作用呢?具体用在哪些情景下?
怪我咯2017-04-17 11:24:12
A_type A_array[1024];
int Count;
在頭檔中,分別被2個c檔包括,這樣相當於在2個c檔中定義了2次,這樣在最後把這2個c檔產生的obj檔連結到一個可執行檔的時候,會導致有重複的定義。一般的做法是把變數的定義放到一個c檔中去,如果其他的c檔需要存取定義在其他c檔中的變量,使用extern關鍵字來宣告這個變數定義在其他的c檔中。
又做了些功課,發現還有些意思。我用的是llvm5.1,其他的平台可能不同。
a.c檔案的彙編結果中,資料是這樣的
main.c 檔案中是這樣的
1. .comm _Count, 4, 2
2. .comm _A_array, 24576, 4
.comm 的符號可能會和其他編譯單元中的符號合併,也就是說2個.c中的_Count和_A_array被合併成一個,這樣不會有符號衝突。
但如果在a.h中加入int k = 0;
在產生的2個.s檔案中都是 .globl _z,這樣在連結的時候就會出現符號衝突。
所以我覺得,樓主還是把出錯訊息貼出來的好。
根據樓主提供的更新
好吧,原來是用c++編譯器編譯的,跟c不一樣。對於第一個錯誤,我認為,struct在c++中有類似class的作用,你的變數a和struct的名字a相同,會被當作這class的constructor,但是constructor是沒有回傳值的,所以報錯。但是由於沒有ms的編譯器,無法確認。你可以把int a改成另外一個變數名字。
第2個錯誤是Count=0已經屬於賦值了,但是Count沒有宣告或定義過,所以出錯。未宣告變數預設為int適用於全域變量,而這個預設在c99中已經取消了,所以,還是在定義的時候給出確定的型別。
如果在頭檔中聲明,最好加上extern,如果另外一個c檔包括了這個頭檔並且用到Count變量,編譯器知道這個變數被定義在其他的檔中,具體位址由linker最後進行解析,這樣就不會報錯。 所以你最好定義在c檔中,然後如果其他c檔也需要存取這個變量,用extern關鍵字來表示這個變數在其他部分定義過了。
ringa_lee2017-04-17 11:24:12
Count = 0;// (2)
這句等同於:
int Count = 0;
未宣告類型的變數預設為整數,未宣告傳回值型別的函數預設為整數。所以你在這裡又定義了一個 Count
變數。
另外全域變數自動初始化為零,所以你這句話沒有用。
void func(A_type A, Color color_type)
這句末尾少了個分號。
(1) 處我看不出什麼問題,你貼原始的報錯資訊吧。你描述的報錯資料語焉不詳。
如果要初始化為常數,直接寫在頭檔裡就可以了。如果要運行時初始化,只能寫在一個函數裡告訴別人先呼叫它。
更新:
如果你想在不同的編譯單位(即單一的(被編譯的).c
檔案)中共用一個變量,請宣告變數的 linkage 為 extern
,即 extern int Count
。
另外,你的 Color
類型沒有定義。被定義的叫 enum Color
。
怪我咯2017-04-17 11:24:12
因為.h檔案可能被包含多次,如果定義放在.h檔案裡面,變數就會被編譯到不同的.o檔案裡面,
當連結的時候就會發生重複定義的錯誤。
所以,定義和初始化放在.c檔裡面。
宣告放在.h裡面,使用這些變數的地方include這個.h檔就行了。
PHPz2017-04-17 11:24:12
http://bbs.chinaunix.net/forum.php?mod=redirect&goto=findpost&ptid=4136506&pid=24175970&fromuid=684069