2016-12-28 271 views
2

我遇到,我似乎无法化解,其中有一个全局变量上声称在声明中唯一的一行被重新声明的问题。我有以下代码:用C共享全局变量typedef定义重新声明

test_regs.h:

#define TEST_REGS_BASE_ADDRESS  0xA0080000 

typedef struct { 
    union { 
     unsigned int data; 
     struct { 
      unsigned int RESERVED  : 16; 
      unsigned int CHAR1  : 8; 
      unsigned int CHAR0  : 8; 
     }; 
    }; 
} TEST_REG_STRUCT; 

typedef struct { 
    TEST_REG_STRUCT      TEST_REG; 
} *TEST_REGS; 

tasks.h:

#ifndef TASKS_H 
#include "test_regs.h" 

volatile TEST_REGS    TST; // This line throws an error 
volatile int     ok_global; 

void func(); 

#define TASKS_H 
#endif 

tasks.c:

#include "tasks.h" 

void func() { 
    TST->TEST_REG.CHAR1 = 0x52; 
    TST->TEST_REG.CHAR0 = 0x51; 
    ok_global++; 
} 

的main.c:

#include "tasks.h" 

main() { 
    TST = (TEST_REGS) TEST_REGS_BASE_ADDRESS; 
    ok_global = 0; 
    func(); 
} 

我试图编译使用以下命令上面的代码(使用GCC的最小版本为LEON3处理器开发):

sparc-elf-gcc -msoft-float -c -g -O2 -o test.o tasks.c main.c

即编译尝试产生以下错误:

tasks.h:4: error: conflicting types for 'TST'

tasks.h:4: error: previous declaration of 'TST' was here

值得注意的是,全局变量,ok_global不POS任何问题;只有可变的,具有In test_regs.h被声明的类型,TST产生上述错误。这意味着错误不能归因于标题tasks.h以某种方式被多次声明。有没有人有任何想法,为什么我写的代码显然是非法的?

我会注意到,如果我摆脱所有标题,除了test_regs.h,并在一个统一的C文件中声明,问题就消失了。另外,我真的必须有test_regs.h头球tasks.h头分离,test_regs.h是机器产生的,而tasks.h不是,将根据使用情况而改变。


好了,因为这显然不是为主持人的头脑乡亲下沉,这不是一个重复的问题。我可以构建我的代码,以满足现有岗位的建议如下(甚至在头吸吮,test_regs.h):

tasks.h:

#ifndef TASKS_H 
#define TASKS_H 
#define TEST_REGS_BASE_ADDRESS  0xA0080000 

typedef struct { 
    union { 
     unsigned int data; 
     struct { 
      unsigned int RESERVED  : 16; 
      unsigned int CHAR1  : 8; 
      unsigned int CHAR0  : 8; 
     }; 
    }; 
} TEST_REG_STRUCT; 

typedef struct { 
    TEST_REG_STRUCT      TEST_REG; 
} *TEST_REGS; 

extern volatile TEST_REGS    TST; 
volatile int     ok_global; 

void func(); 

#endif 

tasks.c:

#include "tasks.h" 

volatile TEST_REGS TST; 

void func() { 
    TST->TEST_REG.CHAR1 = 0x52; 
    TST->TEST_REG.CHAR0 = 0x51; 
    ok_global++; 
} 

为主。C:

#include "tasks.h" 

main() { 
    TST = (TEST_REGS) TEST_REGS_BASE_ADDRESS; 
    ok_global = 0; 
    func(); 
} 

编译命令:

sparc-elf-gcc -msoft-float -c -g -O2 -o test.o tasks.c main.c

结果:

tasks.h:20: error: conflicting types for 'TST'

tasks.c:3: error: previous declaration of 'TST' was here

有一些具体的事情到TST是BRE全球共享;这不仅仅是一般的“我该如何分享全局变量”的问题。

+0

将'#define TASKS_H'移动到文件的顶部,紧接在'#ifndef TASKS_H'之后。 – e0k

+1

不要'typedef'指针,这是一个可怕的想法。除非它们是100%不透明类型。 –

+1

e0k,感谢您的建议,但是这并没有解决问题。另外,我不认为'test_regs.h'可以被多次获取,因为你的建议似乎暗示了,因为'ok_global'不会出现同样的重新声明错误。 – user3570982

回答

3

变量TSTok_global在tasks.h中定义的。由于main.c和tasks.c都包含这个头文件,所以这两个模块都定义了这些变量。当这些模块被连接在一起时,你会得到多个定义的错误。

全局变量应该是定义为在一个.c文件中。任何需要引用它的.c文件都应该包含一个头文件,该头文件具有此全局的声明。一个声明说“这个变量存在于某个地方”,但并没有确切地说出在哪里。

在tasks.h,你声明变量是这样的:

extern volatile TEST_REGS    TST; 
extern volatile int     ok_global; 
void func(); 

然后你在tasks.c定义它们:

#include "tasks.h" 

volatile TEST_REGS    TST; 
volatile int     ok_global; 

void func() { 
    TST->TEST_REG.CHAR1 = 0x52; 
    TST->TEST_REG.CHAR0 = 0x51; 
    ok_global++; 
} 

注意,你已经与func这样做功能。区别在于变量声明需要关键字extern,而函数声明不需要。

+0

但是,如果你想要一致性,你也可以声明函数'extern'。这对他们来说恰恰是多余的。 –

+0

恭敬地说,那不是什么事情。忽略了包含'tasks.h'头文件的宏定义以排除多个声明,并且忽略了'ok_global'编译没有错误的事实。这个问题是特定于'TST'的。另外,当我用'extern'在'tasks.h'中声明'TST',然后在'tasks.c'中声明'extern'时,我仍然得到'previous declaration'错误;它只是表示前面的声明是在'tasks.c'而不是'tasks.h'中。 – user3570982

+0

@ user3570982宏守卫针对给定源模块中多次包含的给定标题进行辩护,但它不会针对多个源模块(包括该标题)进行防御,并且该标题包含像您一样的定义。至于'ok_global',链接器可能只捕获重复变量的第一个实例。尝试上述更改并查看它是如何工作的。 – dbush