重定义概念

重定义是什么

重定义就是定义了多次
  
一般解决重定义的方法是用宏指令 ifndef endif .但是这个方法只能解决重复包含同一个文件的问题. 
如果多个文件中对同一个符号进行了定义,也会出现重定义的问题
  
为什么会出现定义多次的问题呢?
回顾一下生成可执行二进制文件的过程

  • 1/预处理
预处理阶段不可能出现重定义,不是说不可能出现,而是不可 能报错
  • 2/编译
编辑的时候因为融合了很多文件,主要是.c文件和.h文件,因为一个.c文件包括很多.h文件.

这里面很可能出现重定义的问题,报错的话都是这么报的.多次声明不会报错

其实我在两个文件中分别 int i; 不会报错

file1: int i = 9;

file2:int i;

也不会报错

file1: int i = 9;

file2:int i = 8;

报错

linux@ubuntu:~/testForEVERYTHING$ gcc -S main.c -o main.o 
In file included from main.c:9:0:
function2.h:8:5: error: redefinition of ‘i’
function1.h:8:5: note: previous definition of ‘i’ was here

这是我故意做的,当然现实情况下不会这么简单地出错.
  • 3/汇编
汇编是按照编译后的文件转二进制的,只要是编译没问题,汇编就没问题
  • 4/链接
链接的时候要根据调用文件中的函数引用 找到 目标文件或者共享目标文件中的原型.有多少个文件就从多少个文件中找,一个文件中有多少个就找多少个.

linux@ubuntu:~/testForEVERYTHING$ gcc function1.o function2.o main.o -o main
function2.o: In function `fun':
function2.c:(.text+0x0): multiple definition of `fun'
function1.o:function1.c:(.text+0x0): first defined here
collect2: ld returned 1 exit status

意思是在 

function2.o 中,有一个 fun 函数 ,fun函数在文件 function2.c中,多重定义

然而说function1.o中的是第一次定义,为什么会出现这种情况呢? 原因是先连接的前面的

linux@ubuntu:~/testForEVERYTHING$ gcc function2.o function1.o main.o -o main    
function1.o: In function `fun':
function1.c:(.text+0x0): multiple definition of `fun'
function2.o:function2.c:(.text+0x0): first defined here
collect2: ld returned 1 exit status

当然,这是我人为故意链接了多个
  
  

##编译实例分析

出现编译时重定义的时候非常多,尤其是在编译第三方源码的时候

在我编译busybox(busybox-1.17.3.tar.bz2)的时候出现了这个问题:

In file included from /usr/include/linux/sysctl.h:25:0,
                 from /usr/include/linux/netfilter.h:6,
                 from /usr/include/linux/netfilter_ipv4.h:8,
                 from networking/tcpudp.c:35:
/usr/include/linux/kernel.h:12:8: error: redefinition of ‘struct sysinfo’
include/libbb.h:107:8: note: originally defined here
make[1]: *** [networking/tcpudp.o] Error 1
make: *** [networking] Error 2


这个意思是在将networking/tcpudp.c编译成networking/tcpudp.o的时候,出现了一个问题

这个问题是编译的时候 一开始 在 include/libbb.h 中声明(我一般称之为声明)了一个struct sysinfo 这样的结构体类型,

然后/usr/include/linux/kernel.h文件中也声明了一个这样的类型

具体是这么包含的(下面这一段是我分析源码得到的,我不知道是不是可以根据log分析出来,因为没有其他问题的log供我分析)

networking/tcpudp.c包含了include/libbb.h 和 /usr/include/linux/netfilter_ipv4.h
/usr/include/linux/netfilter_ipv4.h包含了/usr/include/linux/netfilter.h
/usr/include/linux/netfilter.h包含了/usr/include/linux/sysctl.h
/usr/include/linux/sysctl.h包含了/usr/include/linux/kernel.h
也就是说
networking/tcpudp.c包含了include/libbb.h,间接包含了/usr/include/linux/kernel.h
然而,这两个.h文件中都有同一个声明,预处理的时候都弄到同一个文件里了,所以出现了重定义的问题

解决方案:/usr/include/linux/sysctl.h文件中包的/usr/include/linux/kernel.h这个删除掉,并添加一个include/libbb.h

链接实例分析

什么时候会出现问题
  • 自己写
自己写的话,一般都是没什么问题的,连接的时候你把它加到 ld 后面就可以了,如果加重了会出现这个问题

所以说自己写和自己写的之间没什么问题
  • 用动态库
动态库的话,如果是gcc自带的库,会根据xxx.h里面的xxx去指定位置找库文件,然后链接进去,其实连接的都是地址吧,我猜.

如果是移植的第三方库,也不会有什么问题,这个是根据gcc选项l后面加的东西去指定位置找的,然后连接进去,其实连接的也是地址.

gcc自带的库之间没什么问题

移植的第三方库会不会和gcc自带的库冲突?好比说移植的第三方库调用了gcc自带的库,但是还是没连接进去,ld会帮忙重定位的.

第三方库之间有没有什么问题?应该会出现一些问题,例如里面可能用了同一个函数,两个库里面都有定义,那么会出现重定义的问题.
  • 用静态库
用静态库的话,gcc自带的静态库之间没什么问题,他们是怎么处理的呢?如果A库用到了B库,A静态库里面是不是包括B静态库里面的东西?

	是不包括的

第三方静态库如果像第三方动态库那样一个函数,两个定义,会不会有什么问题?静态库里面包没包gcc自带的静态库?

	两个定义,自然会有问题

	静态库里面不包括gcc自带的静态库

实例分析

------------------------------
  1
In file included from 2.h:8:0,
                 from main.c:11:
22.h:8:5: error: redefinition of ‘i’
 int i = 10;
     ^
In file included from 1.h:8:0,
                 from main.c:10:
11.h:8:5: note: previous definition of ‘i’ was here
 int i = 9;
     ^
------------------------------
   2    
In file included from main.c:11:0:
2.h:8:5: error: redefinition of ‘i’
 int i = 10;
     ^
In file included from 1.h:8:0,
                 from main.c:10:
11.h:8:5: note: previous definition of ‘i’ was here
 int i = 9;
     ^
------------------------------
  3     
main.c:13:5: error: redefinition of ‘i’
 int i = 10;
     ^
In file included from 1.h:8:0,
                 from main.c:10:
11.h:8:5: note: previous definition of ‘i’ was here
 int i = 9;
     ^
----------------------------------------------------
编译问题
第1个示例中的 一个 i 定义在 22.h 	中,另一个 i 定义在 11.h 中
第2个示例中的 一个 i 定义在 2.h 	中,另一个 i 定义在 11.h 中
第3个示例中的 一个 i 定义在 main.c 中,另一个 i 定义在 11.h 中
----------------------------------------------------

function1.o: In function `fun':
function1.c:(.text+0x0): multiple definition of `fun'
function2.o:function2.c:(.text+0x0): first defined here
collect2: ld returned 1 exit status
----------------------------------------------------
连接问题
编译成function1.o 的 function1.c 中 有 fun 的定义
编译成function2.o 的 function2.c 中 有 fun 的定义
----------------------------------------------------
In file included from /usr/include/linux/sysctl.h:25:0,
                 from /usr/include/linux/netfilter.h:6,
                 from /usr/include/linux/netfilter_ipv4.h:8,
                 from networking/tcpudp.c:35:
/usr/include/linux/kernel.h:12:8: error: redefinition of ‘struct sysinfo’
include/libbb.h:107:8: note: originally defined here
make[1]: *** [networking/tcpudp.o] Error 1
make: *** [networking] Error 2
----------------------------------------------------
编译问题
编译成 networking/tcpudp.o 的 networking/tcpudp.c 中包含的 include/libbb.h 声明了 struct sysinfo
编译成 networking/tcpudp.o 的 networking/tcpudp.c 中包含的 /usr/include/linux/netfilter_ipv4.h 包含的
/usr/include/linux/netfilter.h 包含的 /usr/include/linux/sysctl.h 包含的 /usr/include/linux/kernel.h 声明了 struct sysinfo
----------------------------------------------------


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值