C/C++中的强符号和弱符号

C/C++中的强符号和弱符号

先看如下场景

// 在1.c中定义了全局变量
int g = 1;
int g2;

同时

// 在2.c中也定义了全局变量
int g = 1;
double g2;

对上边C文件编译时会报符号重复定义(Multiple Definition)的错误,这是因为在多个源文件中定义了同名的全局变量,且都已初始化。报错如下

2.o: multiple definition of `g'
1.o: first defined here

在C中,默认情况下,编译器认为函数和已初始化的全局变量为强符号(Strong Symbol),未初始化的全局变量为弱符号(Weak Symbol)。强符号是因拥有已确定的初始化数据,变量有值,函数有函数体;弱符号则是因符号还未被初始化,无确定数据,只是个声明。

链接器对重复定义变量(强/弱符号)的处理规则:

  1. 不能定义多个强符号,即不同.o目标文件里变量/函数不能重复定义,若有多个同名强符号,链接器报符号重定义的错误。
  2. 若一符号在其中一个目标文件中是强符号,其他是弱符号(如只声明,无初始化),则选择强符号。
  3. 若一符号在所有目标文件中都是弱符号,则选占内存空间最大的一个。如上边例子的g2会占8字节,可见若出问题则很难排查。(此点参考其他博客资料,最新编译器验证是不成立的,见下文例子)

特注:上边第3点在实测中不一定对,用sizeof会是本文件变量的内存大小。

//gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)
// main.c
#include<stdio.h>
int w2;
int main() {
        printf("sizeof(w2)=%ld in main.c", sizeof(w2));
        func();
        return 0;
}

//test.c
#include<stdio.h>
double w2;
void func() {
        printf("sizeof(w2)=%ld in test.c\n", sizeof(w2));
}
//编译 gcc main.c test.c
//运行结果:
sizeof(w2)=4 in main.c
sizeof(w2)=8 in test.c
//同样这个例子,用g++编译的话,则会报重复定义的错误了
/tmp/ccqUe8kE.o:(.bss+0x0): `w2'被多次定义
/tmp/cczTldSS.o:(.bss+0x0):第一次在此定义
collect2: error: ld returned 1 exit status

使用gcc编译,可用_attribute_((weak))强制定义一符号为弱符号,可用于解决重复定义的报错(用于调试用,实际工程还是别这么干了)。见如下例子:

extern int e1; //引用外部变量,非强符号也非弱符号,作用是告诉编译器别报未定义,这个变量在链接时能找到。

int w1;//弱符号
__attribute__((weak)) int w2 = 1; //弱符号
__attribute__((weak)) void func() { //弱符号,如果func函数在其他地方也被定义了,不加__attribute__((weak))会报Multiple Definition错误
    printf("弱符号函数");
}
int s1 = 1;//强符号
void main() {
    printf("强符号");
}

弱符号主要用于解决一些库的冲突或引入一些库,防止符号冲突。再看个上面列的第二规则的例子(注意是两个c文件):

//gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)
//以下内容是test.c内容
#include<stdio.h>
int w1 = 2;
void func() {
        printf("weak symb =func in test\n");
}
//以下是main.c内容
#include<stdio.h>
__attribute__((weak)) int w1 = 1;
__attribute__((weak)) void func() {
        printf("weak symb =func in main\n");
}
int main() {
        printf("w1=%d\n", w1);
        func();
        return 0;
}
//编译: gcc main.c test.c 运行结果,打印出强符号的值 (g++ main.c test.c编译的结果也一致)
w1=2
weak symb =func in test

当然,_attribute_((weak))只对链接器有效,对编译器无效,在编译器没有强/弱符号之分,如在同一文件内,定义两个同名变量,则报重复定义错误,如例子

#include<stdio.h>
__attribute__((weak)) int w1 = 1;
int w1 = 2;
int main() {
        printf("w1=%d\n", w1);
        return 0;
}
//编译gcc test_sam.c
error: redefinition of ‘w1’
 int w1 = 2;
     ^~
note: previous definition of ‘w1’ was here
 __attribute__((weak)) int w1 = 1;
posted @ 2023-05-13 17:37  00lab  阅读(164)  评论(0编辑  收藏  举报