首頁  >  問答  >  主體

程序员 - C/C++头文件声明变量的问题

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, 有什么作用呢?具体用在哪些情景下?

大家讲道理大家讲道理2764 天前540

全部回覆(6)我來回復

  • 怪我咯

    怪我咯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檔案的彙編結果中,資料是這樣的

    1. .globl _Count
    2. .comm _A_array, 24576,4

    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關鍵字來表示這個變數在其他部分定義過了。

    回覆
    0
  • ringa_lee

    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

    回覆
    0
  • 怪我咯

    怪我咯2017-04-17 11:24:12

    因為.h檔案可能被包含多次,如果定義放在.h檔案裡面,變數就會被編譯到不同的.o檔案裡面,
    當連結的時候就會發生重複定義的錯誤。
    所以,定義和初始化放在.c檔裡面。
    宣告放在.h裡面,使用這些變數的地方include這個.h檔就行了。

    回覆
    0
  • PHPz

    PHPz2017-04-17 11:24:12

    http://bbs.chinaunix.net/forum.php?mod=redirect&goto=findpost&ptid=4136506&pid=24175970&fromuid=684069

    回覆
    0
  • 天蓬老师

    天蓬老师2017-04-17 11:24:12

    我覺得是.c檔是有作用域的

    回覆
    0
  • 高洛峰

    高洛峰2017-04-17 11:24:12

    1.把a.h中的A_type A_array[1024];int Count;寫到原始檔
    2.最適合的方法是int Count = 0;

    回覆
    0
  • 取消回覆