ホームページ  >  に質問  >  本文

程序员 - 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日前539

全員に返信(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
  • キャンセル返事