在用C语言开发大型的工程中,由于文件众多,在各种机缘巧合下会出现全局变量重复定义,那假如出现这种情况是什么现象呢

首先来看看一个全局变量重复定义用例

例一:

testA.c文件

#include <stdio.h>
#include <stdlib.h>extern void printf_testB();
int a;int main()
{a=10;printf("testA.c a=%d,&a=%p\n",a,&a);printf_testB();return 0;
}

testB.c文件

#include <stdio.h>
#include <stdlib.h>int a=20;void printf_testB()
{printf("testB.c a=%d,&a=%p\n",a,&a);
}

在上面的两个文件中分别定义了整型变量a,并且都赋值了,在各自的文件中打印a的值和地址,在这里大家可以先猜一猜,两个printf打印出来的a分别是多少?

利用gcc编译两个文件

[root@localhost fno-common]# gcc testA.c testB.c -o targetExe
[root@localhost fno-common]#
[root@localhost fno-common]# ll
总用量 20
-rwxr-xr-x 1 root root 8608 2月   2 16:09 targetExe
-rwxrwxrwx 1 root root  177 2月   2 15:55 testA.c
-rwxrwxrwx 1 root root  120 2月   2 15:55 testB.c
[root@localhost fno-common]#

可以看到在不带任何检查参数的情况,没有任何报错,运行目标文件

[root@localhost fno-common]# ./targetExe
testA.c a=10,&a=0x601034
testB.c a=10,&a=0x601034

可以看到两个文件里打印出来的变量a和a的地址是完全一样的,指向的是同一块内存,而且a的值就是testA文件里的值。

再看一个例子,假如不对testA.c中的全局变量进行赋值呢

例二:

testA.c文件

#include <stdio.h>
#include <stdlib.h>extern void printf_testB();
int a;int main()
{printf("testA.c a=%d,&a=%p\n",a,&a);printf_testB();return 0;
}

testB.c文件不变

看看运行的结果

[root@localhost fno-common]# ./targetExe
testA.c a=20,&a=0x601034
testB.c a=20,&a=0x601034

这次运行的结果变成了testB文件里a的值了,并且和例一种的一样,变量a和a的地址是完全一样的。

这是为什么呢?

首先说一下C语言中的弱符号和强符号

1,弱符号:未初始化的变量是弱符号

2,强符号:已初始化的变量是强符号

对于链接器来说,所有的全局符号可分为两种:强符号(Strong symbols),弱符号(Weak symbols)。gcc的attribute中有个__attribute__((weak)),就是用来声明这个符号是弱符号的。gcc手册中这样写道:

The weak attribute causes the declaration to be emitted as a weak symbol rather than a global. This is primarily useful in defining library functions which can be overridden in user code, though it can also be used with non-function declarations. Weak symbols are supported for ELF targets, and also for a.out targets when using the GNU assembler and linker.

对于这个gcc扩展,这里作了一个简洁的介绍。我们来看更通用的情况。;)

一般来说,函数和已初始化的变量是强符号,而未初始化的变量是弱符号。对于它们,下列三条规则适用:

1.  同名的强符号只能有一个。
        2. 有一个强符号和多个同名的弱符号是可以的,但定义会选择强符号的。
        3. 有多个弱符号时,链接器可以选择其中任意一个。

上述例一和例二中,testA.c的全局变量a没有初始化,是弱符号,而testB.c的全局变量初始化了是强符号,则根据上述的规则二,例一种在testA.c中全局变量a指向的是testB.c中定义全局变量的地址,在testA.c中对a进行赋值,则改变了a的值。而在例二中testA.c并没有对a赋值,所以取得还是20。

可以看到如果没注意到这个问题,本意是在testA.c中对定义的全局变量进行赋值,给相关功能使用,结果意外的改变了testB.c中的值,危害不言而喻。那如何避免这种情况呢,至少要检查的出来,给个提醒。

避免这种错误的一个方法是,给gcc加上-fno-common选项,加上该选项后再进行编译

[root@localhost fno-common]# gcc testA.c testB.c -o targetExe -fno-common
/tmp/cc8StOtH.o:(.data+0x0): multiple definition of `a'
/tmp/cc3yyF0p.o:(.bss+0x0):第一次在此定义
collect2: 错误:ld 返回 1

可以看到编译不通过,给出了报错,有多重定义变量a。

那么,如果出现了这种多重定义的问题,怎么改呢

1,如果确定两个变量只是碰巧重名了,则很简单改掉一个,不重名即可

2,如果确定两个变量是要用同一个,则在使用的文件里加extern,告诉编译器这是用的同一个

当然该参数还有其他作用,可参考以下文章:

https://blog.csdn.net/yyz_1987/article/details/107569192

C语言全局变量重复定义检查-fno-common相关推荐

  1. 函数或全局变量重复定义时会怎样?

    可能有些朋友第一反应是,那肯定是编译不过喽: // fun.c #include void func() {printf("编程珠玑\n"); }// main.c #includ ...

  2. C语言——全局变量的定义与声明

    转自: https://www.cnblogs.com/amanlikethis/p/3319744.html C语言中全局变量的定义与声明困扰着许多C语言初学者.本文讲述了全局变量定义与声明的用法, ...

  3. 解决C/C++语言中全局变量重复定义的问题

    前言 今天,在整理自己的代码的时候,考虑到我写的代码从一至终都是在一个cpp文件里面.于是,想把自己的代码中的各个模块分离开来,以便更好地阅读和管理. 遇到的问题 我的做法是: 宏定义.结构体定义.函 ...

  4. 关于C语言全局变量的定义和用法

    在单片机编程中经常会用到全局变量,假设要在a.c文件中用到b.c文件定义的变量,我们应该怎样定义.怎样引用才能让程序看起来干净整洁呢?下面简单记录一下 假设现在有3个c文件,a.c.b.c.main. ...

  5. C++中不允许重复定义全局变量

    文章目录 1 C++中不允许重复定义全局变量 1 C++中不允许重复定义全局变量 C++中不允许重复定义全局变量: 在C语言中,重复定义多个同名的全局变量是合法的. 在C++中,不允许定义多个同名的全 ...

  6. extern 用法,全局变量与头文件(重复定义)

    转自 https://www.cnblogs.com/chengmin/archive/2011/09/26/2192008.html 当你要引用一个全局变量的时候,你就要声明,extern int  ...

  7. c语言寄存器头文件共用重复定义,C语言头文件的使用

    让我们的思绪乘着时间机器回到大学一年级.C原来老师正在讲台上讲着我们的第一个C语言程序: Hello world! 文件名 First.c main() { printf("Hello wo ...

  8. C语言中如何定义全局变量

    C语言中如何定义全局变量 C/C++ 2010-09-06 13:01:39 阅读590 评论0   字号:大中小 订阅 众所周知,全局变量在被定义后,系统会为全局变量分配内存并且它还可以被其他模块通 ...

  9. C语言全局变量定义方法

    C语言全局变量定义方法 今天调试系统的时候,需要定义几个全局位变量,定义好后一编译,发现错误一大堆,错误基本都是位变量定义时产生的.以前也定义过全局变量啊,但是先前怎么没错误?瞎折腾了一会最后还是发现 ...

  10. c51语言定义全局变量,全局变量的定义和使用

    在用VB开发软件时,经常需要在不同的窗体间共享数据,但在过多的使用全局变量时不便于软件的调试和修改.通常有两种解决方法. 第一种方法:定义全局变量,然后在各个窗体中直接使用,例如 Public str ...

最新文章

  1. javascript模块化、模块加载器初探
  2. HDU 1724 Ellipse ——Simpson积分
  3. 计算机系学生的职业生涯作文,医学生职业生涯规划的作文800字
  4. boost::hana::reverse用法的测试程序
  5. Writing your first Django app--Django 第一步
  6. ASP.NET获取客户端、服务器端基础信息
  7. 张正友相机标定Opencv实现以及标定流程标定结果评价图像矫正流程解析(附标定程序和棋盘图)
  8. 结构化数据存储,如何设计才能满足需求?
  9. linux上用selenium登录新浪微博,获取用户关注的用户id
  10. 基于多模态常规技术的芒果叶片病害识别新模型
  11. 绿标2.0隐私权限解读——应用分类及对应权限展示(下)
  12. 阿里云云计算 42 CDN中的常用名词
  13. 软件测试——集成测试篇
  14. 下列c语言表达式正确,C语言试题-10(含答案
  15. 微信小程序弹窗有输入框且可以使用名文和密文输入
  16. Thoughtworks
  17. 点估计与区间估计、置信区间、置信水平
  18. 内容过于真实,可能会引起不适-----程序员去面试的梗!面试官:“哦了,明天来上班吧”
  19. 晶体DSX321G被公认的车载晶振在无人货车上也将功能发挥的淋漓精致
  20. unity 显示 html页面,unity打开外部或本地html网页方法

热门文章

  1. 基于Flink建设流批一体实时数仓
  2. flash静态的农夫走路_FLASH静态图形图像演示课件
  3. 思岚科技A1,A2雷达驱动安装
  4. 宾馆客房管理系统-vue前端开发
  5. js将html替换字符串,js 替换字符串指定内容 javascript 替换指定位置的字符
  6. ADB 环境变量配置教学
  7. vue移动端app项目
  8. pywinauto实现微信消息自动发送
  9. odoo报表内部和外部布局
  10. 产品经理入职四部曲—带你顺利度过试用期