静态库 头文件中定义变量

aqiang_00 2008-10-15 04:44:36
看到同事这么用了一个全局变量,结果编译连接时提示重复定义,有点不明白。大致如下:
//test.h
#ifndef __TEST_H__
#define __TEST_H__
...
int test_a = 0;
...
#endif

//test.c
#include "test.h"
....

test.c 被编成功地译成一个静态库libtest.a

//main.c
#include "test.h"
int main(int argc,char*argv[])
{
.....
return 0;
}
编译main.c时把libtest.a链接进来,链接时报错说test_a被重复定义!!

我不明白的是:test.h已经有了#ifndef __TEST_H__,应该不会被重复应用了,为什么还会出现重复定义呢??当然没有静态库时,直接把test.c编译成test.o,把main.c编译成main.o,然后链接成可执行文件,这样是完全正确的(尽管不提倡头文件中定义变量)。我认为,之所以说重复定义,应该是说main.c中#include "test.h"时test_a被定义,然后连接libtest.a时libtest.a中test_a也被定义。但libtest.a中#ifndef __TEST_H__就不起作用了吗?

请高人指点迷津!谢谢!





...全文
1428 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
duanhjlt 2008-10-19
  • 打赏
  • 举报
回复
[Quote=引用楼主 aqiang_00 的帖子:]
看到同事这么用了一个全局变量,结果编译连接时提示重复定义,有点不明白。大致如下:
//test.h
#ifndef __TEST_H__
#define __TEST_H__
...
int test_a = 0;
...
#endif

//test.c
#include "test.h"
....

test.c 被编成功地译成一个静态库libtest.a

//main.c
#include "test.h"
int main(int argc,char*argv[])
{
.....
return 0;
}
编译main.c时把libtest.a链接进来,链接时报错…
[/Quote]

//test.h
#ifdef __TEST_H__
#define TEST_VAR
#else
#define TEST_VAR extern
#endif

TEST_VAR int a;//声明,在test中被声明, 在main.c被外部引用


//test.c
#define TEST_VAR
#include "test.h"
int a=0;

#include "test.h"
int main(int argc,char*argv[])
{
.....
return 0;
}
帅得不敢出门 2008-10-19
  • 打赏
  • 举报
回复
防止重复包含
once_and_again 2008-10-17
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 guosha 的回复:]
当你编译成.o时,#ifndef会起作用,但是当你编译成静态库后#ifndef就没法子起作用了,链接的时候当然会出错啦。

一般来说,.h文件只提供声明,定义都放在.c文件里,比如你这里,你把int test_a = 0放到.c文件里去,在.h文件里加上extern test_a就不会出问题了。
[/Quote]....
realdragon2 2008-10-16
  • 打赏
  • 举报
回复
他的意思是说, 动态库的地址空间和主程序的地址空间不同使得变量不会出现重复的情况? 也就是, 同样变量名的变量位于不同的内存块.~~
[Quote=引用 3 楼 guosha 的回复:]
你说的上面是说分别把test.c跟main.c编译成.o文件后再单独去链接吗?
你可以链接成功? 不可能吧.这样跟使用静态库没什么两样哦,应该也是链接会出现重复定义的!!!
[/Quote]
weidong0210 2008-10-16
  • 打赏
  • 举报
回复
linux 下全局变量建议不要写在.h文件中 因为你在多个文件中引用该.h文件,生成.o文件时,编译器就产生问题了。
解决问题:
1.将全局变量可以写在.cpp下
2.要用的地方加(比如) extern int g_inumber;
快乐田伯光 2008-10-16
  • 打赏
  • 举报
回复
不初始化的话没有问题,有可能把其中的一个理解成了声明。
快乐田伯光 2008-10-16
  • 打赏
  • 举报
回复
.h文件里遵循只声明不定义就不会出现重复定义。如果你在.h里定义了一个函数,有多个文件包含这个头文件的话也会出现重复定义。
aqiang_00 2008-10-16
  • 打赏
  • 举报
回复
guosha 说的正确,“当然没有静态库时,直接把test.c编译成test.o,把main.c编译成main.o,然后链接成可执行文件,这样是完全正确的”这句话我说错了。当时没有验证这个问题,不好意思:-)我们不要讨论它了。

问题似乎稍微清除了一点:test.c不管是编译成静态库(xxx.a),还是目标文件(xxx.o),test_a都在.bss段,编译main.o时test_a也被编译在了.bss段(由于我们在main.c中包含了test.h),这样链接时程序的.bss段里就出现了重复定义?对于这样的问题我没有深究过,只是知道程序里有什么code段、bss段等,望指点!

补充:test_a不被初始化时,不会出现重复定义的错误报告,我试过了。

请问:我们在头文件使用的#ifndef _XXXX_
#define _XXXX_
,用来防止头文件重复引用,那么还有其他类似情况也会出现重复定义吗?
realdragon2 2008-10-16
  • 打赏
  • 举报
回复
汗~~ 还以为你接你楼主的话呢....
[Quote=引用 6 楼 guosha 的回复:]
我的意思说,楼主说的分别编译成.o然后再链接,也一样会报同样的错。楼主说不会报错,肯定是楼主哪里搞错了。

引用 5 楼 realdragon2 的回复:
他的意思是说, 动态库的地址空间和主程序的地址空间不同使得变量不会出现重复的情况? 也就是, 同样变量名的变量位于不同的内存块.~~
引用 3 楼 guosha 的回复:
你说的上面是说分别把test.c跟main.c编译成.o文件后再单独去链接吗?
你可以链接成功? 不可能吧.这样跟使用静态库…
[/Quote]
快乐田伯光 2008-10-16
  • 打赏
  • 举报
回复
我的意思说,楼主说的分别编译成.o然后再链接,也一样会报同样的错。楼主说不会报错,肯定是楼主哪里搞错了。

[Quote=引用 5 楼 realdragon2 的回复:]
他的意思是说, 动态库的地址空间和主程序的地址空间不同使得变量不会出现重复的情况? 也就是, 同样变量名的变量位于不同的内存块.~~
引用 3 楼 guosha 的回复:
你说的上面是说分别把test.c跟main.c编译成.o文件后再单独去链接吗?
你可以链接成功? 不可能吧.这样跟使用静态库没什么两样哦,应该也是链接会出现重复定义的!!!
[/Quote]
xhs_lh04 2008-10-16
  • 打赏
  • 举报
回复
楼上的正解
blackbillow 2008-10-15
  • 打赏
  • 举报
回复
In C, global is treated as a tentative definition because it is without explicit initialization. A tentative definition can occur multiple times within the program. Those multiple instances are collapsed by the link editor, and a single instance is placed within the portion of the program data segment reserved for uninitialized global objects.

In C++, tentative definitions are not supported because of the implicit application of class constructors. (Admittedly the language could have distinguished between class objects and Plain Ol' Data, but doing so seemed an unnecessary complication.) global, therefore, is treated within C++ as a full definition (precluding a second or subsequent definition). One difference between C and C++, then, is the relative unimportance of the BSS data segment in C++. All global objects within C++ are treated as initialized.

摘自Inside the C++ Object
快乐田伯光 2008-10-15
  • 打赏
  • 举报
回复
你说的上面是说分别把test.c跟main.c编译成.o文件后再单独去链接吗?
你可以链接成功? 不可能吧.这样跟使用静态库没什么两样哦,应该也是链接会出现重复定义的!!!
nevil 2008-10-15
  • 打赏
  • 举报
回复
你编绎的时候库和主程序是分开编绎的,仅在链接时关联,所以#ifndef这时是不起作用的.

使用静态库时库的代码与符号表在主程序内会有一份拷贝,所以这里会出现重复定义.
使用动态库时,主程序只时在运行时计算库函数入口地址而不会有库代码的拷贝,所以不会出现重得定义.
快乐田伯光 2008-10-15
  • 打赏
  • 举报
回复
当你编译成.o时,#ifndef会起作用,但是当你编译成静态库后#ifndef就没法子起作用了,链接的时候当然会出错啦。

一般来说,.h文件只提供声明,定义都放在.c文件里,比如你这里,你把int test_a = 0放到.c文件里去,在.h文件里加上extern test_a就不会出问题了。

23,121

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧