千家信息网

如何理解函数或全局变量重复定义

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章主要讲解了"如何理解函数或全局变量重复定义",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"如何理解函数或全局变量重复定义"吧!可能有些朋友第一反
千家信息网最后更新 2026年11月03日如何理解函数或全局变量重复定义

这篇文章主要讲解了"如何理解函数或全局变量重复定义",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"如何理解函数或全局变量重复定义"吧!

可能有些朋友第一反应是,那肯定是编译不过喽:

// 来源:公众号【编程珠玑】 // 作者:守望先生 // fun.c #include void fun() {     printf("编程珠玑\n"); }  // main.c #include void func() {     printf("公众号\n"); } int main(void) {     func();     return 0; }

编译:

$ gcc -o main main.c fun.c /tmp/ccKeACRk.o: In function `fun': fun.c:(.text+0x0): multiple definition of `fun' /tmp/cc4ezgqh.o:main.c:(.text+0x0): first defined here collect2: error: ld returned 1 exit status

可以看到这里报错了,因为fun重复定义了。

但是重复定义就会报错,会编译不过吗?不全是!

再看下面的代码:

// 来源:公众号【编程珠玑】 // 作者:守望先生 //var.c int num; void change() {     num = 1023; }  //main.c #include void change(); int num = 1024; int main(void) {     printf("before:num is %d\n", num);     change();     printf("after:num is %d\n", num);     return 0; }

输出结果:

before:num is 1024  after:num is 1023

从结果中可以看到,虽然num被定义了两次,但是仍然可以编译通过,并且正常运行。这又是为什么呢?

符号

在说明今天重点分享的内容之前,先简单了解一下什么是符号。在《hello程序是如何变成可执行文件的》中讲到过,ELF文件生成的最后阶段会经历链接,而链接阶段正是基于符号才能完成。每个目标文件都会有一个符号表。而链接过程正是通过符号表中的符号,将不同的目标文件"粘"在一起,形成最后的库或者可执行文件。要查看一个目标文件的符号信息也很容易:

// symbol.c #include int symbol = 1024; int func_symbol() {     return 0; }

编译:

$ gcc smbol.c #编译 $ nm symbol.o #查看符号信息 0000000000000000 T func_symbol 0000000000000000 D symbol

通过nm命令就可以查看符号信息,这里就有我们的func_symbol函数和全局变量symbol的符号。

关于nm的使用,在《几个命令了解ELF文件的秘密》也有介绍。

除了上面提到的全局符号,目标文件中还有其他符号信息,不过这不是本文关注的重点。

强符号与弱符号

对于C/C++语言来说,编译器默认函数和初始化了的全局变量为强符号,未初始化的全局变量为弱符号。当然也可以通过

__attribute__((weak))

来定义一个强符号为弱符号。

通过下面的例子来看看哪些是强符号,哪些是弱符号:

#include int weak; // 未初始化全局变量,弱符号 int strong = 1024; // 已初始化全局变量,强符号 __attribute__((weak)) int weak1 = 2222; // 使用标识修饰的弱符号 int main(void) {     printf("编程珠玑\n");     return 0; }

注意,这里的强符号与弱符号都是针对定义来说的。

同名时,用哪个?

对于多重定义,即标题提到的变量重名时,链接器有它的处理规则:

  • 1.强符号不允许重复

  • 2.有一个强符号和多个弱符号,使用强符号

  • 3.多个弱符号,则随意选择一个

关于第一点,在最开始的例子中你已经见到了,最常见的情况就是你重复定义了变量或者函数等等。

而第二点也有示例,示例中,虽然定义了两个num,但是var.c中未初始化的num是弱符号,main.c中的num是强符号,这种情况下编译正常。只是最终会使用强符号的num。

再看一个第三点的例子也是类似,当其中main.c的num无初始化时,也是可以编译过的。这种情况下的误用也就罢了,如果是重复的符号,但是类型不同,问题就更大了,即var.c的内容如下:

//var.c double num; void change() {     num = 1023; }

这里的num变成了double,再次编译运行,你会发现意想不到的结果:

before:num is 1024  after:num is 0

为什么修改后是0?原因在于double类型的数据存储与int类型数据存储格式不一样,且它们占用空间长度都不一样,在本文例子中,double占用8字节,而int占用4字节。

总之,这不是我们想要的结果,最终的后果可能比我们想象的要严重,要更难发现。

感谢各位的阅读,以上就是"如何理解函数或全局变量重复定义"的内容了,经过本文的学习后,相信大家对如何理解函数或全局变量重复定义这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

符号 变量 全局 编译 文件 函数 例子 信息 内容 情况 珠玑 目标 结果 链接 编程 公众 类型 学习 不同 这不 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 百单网互联网科技有限公司 互联网科技活动banner 互联网科技有限公司图片 互联网巨头反垄断金融科技 关于新基建和互联网科技 凡科互联网科技 互联网科技小额贷款 互联网科技论坛 上海亿帐通互联网科技 成都仁贤领冠互联网科技有限公司 山东吉时兔互联网科技有限公司 宁波青枫互联网科技有限公司 互联网科技热点资讯 福州新华互联网科技学校 知乎 互联网系的金融科技公司 南平创想时代互联网科技有限公司 华夏互联网科技业 恒生互联网科技业指数调整周期 互联网科技资金流入 抖集互联网科技技术咨询 深圳市人人互联网科技有限公司 互联网科技公司电话 互联网科技ppt模板 时间互联网络科技 互联网 科技服务平台 深圳卡尔迅互联网科技有限公司怎么样 中化能源互联网科技招聘 2021互联网科技公司排名 智帮互联网科技公司最近动向 福州德业互联网科技
0