C语言中的强符号与弱符号
参考《程序员的自我修养》
参考 C语言中的强符号与弱符号
符号重复定义
main.c
int a = 100;
int main(){
printf("%d\n",a);
return 0;
}
other.c
int a = 10;
编译
gcc main.c other.c
编译结果
clang
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1
gcc
multiple definition of `a'
比如:我们在目标文件A和目标文件B都定义了一个全局整形变量global,并将它们都初始化,那么链接器将A和B进行链接时会报错!
这种符号的定义可以被称为强符号(Strong Symbol)
函数,初始化了的全局变量为强符号
未初始化的全局变量为弱符号
注意
下面的__attribute__((weak))
是gcc提供的将强符号转为弱符号的关键字
main.c
extern int ext;
int weak1;
int strong = 1;
int __attribute__((weak)) weak2 = 2;
int main()
{
printf("%d,%d,%d\n", weak1,strong,weak2);
return 0;
}
test.c
int weak1 = 100;
//int strong = 100; //multiple definition of `strong'
int weak2 = 200;
编译gcc mainc test.c
结果100,100,200
这里有人会将强符号理解为extern,因为在mainc和test.c两个模块中共享全局变量,你可以打印地址(地址是一样的)。
但两者是本质不同的
extern 本质就是声明变量,告诉linker去其他模块找定义。
而强符号和弱符号可是实打实的定义。虽然我们说弱符号没有初始化。
关于定义与声明的区别,请看这篇文章c语言的定义与声明
说实话,我也是看了《程序员的自我修养》之后,才知道有强符号和弱符号的概念,而且在mac上试了一下,不行,只能在gun linux上玩。看了各个厂商在这方面的实现出入还很大!
结论
同名的强符号只能有一个,否则编译器报"重复定义"错误
如果去掉test.c中strong的定义,就会报"重复定义"错误。
我的理解
首先,从上面的例子可以看到,两个模块共享变量。但是又和extern不同,extern就是声明,完全没有分配内存。但是这里可是定义,照样共享内存了!
例子1
weak.c
void __attribute__((weak)) f();
int main(void)
{
if (f)
f();
return 0;
}
编译
gcc weak.c
结果
通过了,并且还能运行!很奇怪吧
例子2
增加一个f.c
#include <stdio.h>
void f(void)
{
printf("hello from f\n");
}
编译
gcc weak.c f.c
结果 hello from f
例子3
修改weak.c
#include <stdio.h>
void __attribute__((weak)) f()
{
printf("hello from weak\n");
}
int main(void)
{
f();
return 0;
}
编译
gcc weak.c
结果 hello from weak
编译
gcc weak.c f.c
结果 hello from f
注意
编译方式不同,结果不同
结论
根据上面三个例子,得到结论:
允许一个强符号和多个弱符号,但定义会选择强符号的。
例1,只有弱符号f,编译通过!没有报
reference f not defined!
例2,3 f.c是强符号,结果执行结果用的是f.c中的f定义
最后一个例子4
main.c
#include <stdio.h>
#include <stdlib.h>
extern int fun(void);
int global_var1 = 0xff00ff00; // 强符号
int main(int argc, const char *argv[])
{
printf("in main.c: &global_var1 = %p", &global_var1);
printf(" global_var1 = %x\n", global_var1);
printf("sizeof(global_var1) = %d\n", sizeof(global_var1));
/////////////////////////////////////////////////////////////////////
fun();
printf("global_var1 = %x\n", global_var1);
printf("global_var2 = %x\n", global_var2);
return 0;
}
test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
double global_var1;
int fun(void)
{
printf("in test.c: &global_var1 = %p", &global_var1);
printf(" global_var1 = %x\n", global_var1);
printf("sizeof(global_var1) = %d\n", sizeof(global_var1));
memset(&global_var1, 0, sizeof(global_var1));
return 0;
}
main.c 和 test.c都有一个global_var1,在main.c中的为强符号,在test.c中的为弱符号.
main.c中的global_var1和test.c中的global_var1引用的时同一块内存区域,只是在两个文件中代表的意义不同
在main.c中代表一个int型变量,在test.c中代表一个double型变量,它们的起始地址相同,但占用内存空间是不同的, 在main.c中占用4个字节,在test.c中占用8个字节,这点从上图的两个sizeof输出结果中可以得到验证
结论
当有多个弱符号相同时,链接器选择占用内存空间最大的那个
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。