首页 > 编程语言 >C/C++中的强符号和弱符号

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

时间:2023-05-13 17:46:42浏览次数:39  
标签:__ 符号 int weak C++ w1 main

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;

标签:__,符号,int,weak,C++,w1,main
From: https://www.cnblogs.com/UFO-blogs/p/17397005.html

相关文章

  • C++趣味编程
    折半查找。1#include<iostream>2usingnamespacestd;3#defineN104intmain()5{6inti,a[N]={-3,4,7,9,13,45,67,89,100,180},low=0,high=N-1,mid,k=-1,m;7cout<<"a数组中数据如下"<<endl;8for(inti=0;i<N;i++)......
  • wsl中c++环境配置
    sudoapt-getinstallnodejssudoapt-getinstallnpmsudoapt-getinstallclangd-12Gettingstarted(llvm.org) ......
  • c++练习
    #include<iostream>usingnamespacestd;classtime{public: inthour; intminute; intsec;};intmain(){ timet1; cin>>t1.hour; cin>>t1.minute; cin>>t1.sec; cout<<t1.hour<<":"; cout<<t1.minute<<":......
  • c/c++零基础坐牢第十一天
    c/c++从入门到入土(11)开始时间2023-05-13 12:24:38结束时间2023-05-13 16:21:58 前言:说到指针,我也显得像个初学者,《深入理解计算机系统》之3.10“综合:理解指针”这样说:“指针……以一种统一方式,对不同数据结构中的元素产生引用”。也有人这么说“当函数以数据的指针为参数时,......
  • C++ OpenCV安装教程
    C++OpenCV编译安装教程环境说明win10+MinGW64+Cmake下载mingw64(版本:12.1.0posix-seh)下载Cmake(版本3.17.5)注:mingw64和cmake下载安装完成后记得把bin目录添加到【环境变量】,如:下载opencv(版本4.6.0,下载后双击exe,选择目录进行解压即可)GitHub加速链接(复制下......
  • 【C++】继承(上)
    @TOC1.继承的使用若有好多类,都有公共的特征,将类中的特性提取出来专门放在一个类中,这个类一般叫做基类或者父类public作为继承方式继承方式共有三种:publicprotectedprivateStuent类内部虽然没有实现name和age,但是它继承了person父类的name和age父类可以叫做基类,子类也可以......
  • 用C++编写一个简单的程序
    本篇文章将介绍如何使用C++编写一个简单的程序,该程序可以接收用户输入并将其转换为整数。在C++中,可以使用标准库中的<iostream>头文件来输出和输入数据。以下是一个简单的C++程序,可以读取用户输入,并将其转换为整数:#include<iostream>usingnamespacestd;intmain(){......
  • C++傅里叶变换
    #include<stdio.h>#include<math.h>#definepi3.1415926typedefstruct{floatre;//reallyfloatim;//imaginary}complex,*pcomplex;complexcomplexadd(complexa,complexb)//复数加{complexrt;rt.re=a.re+b.re;......
  • C++是如何工作的
     在#符号之后的都是预处理语句,编译器收到源文件,看到这条语句就先处理这条预处理语句因为在实际编译发送之前就被处理了 include含义:它需要找到这文件,将这个文件所有内容拷贝到现在的文件内,这些文件就是头文件 iostream:我们需要被调用的函数的声明std::out可以让我们在终......
  • 1011 A+B 和 C(C++)
    一、问题描述:给定区间[−231,231]内的3个整数 A、B 和 C,请判断 A+B 是否大于 C。输入格式:输入第1行给出正整数 T (≤10),是测试用例的个数。随后给出 T 组测试用例,每组占一行,顺序给出 A、B 和 C。整数间以空格分隔。输出格式:对每组测试用例,在一行中输出 C......