文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2024-04-02 19:55

关注

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

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

// 来源:公众号【编程珠玑】 // 作者:守望先生 // fun.c #include<stdio.h> void fun() {     printf("编程珠玑\n"); }  // main.c #include<stdio.h> 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<stdio.h> 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<stdio.h> 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<stdio.h> int weak; // 未初始化全局变量,弱符号 int strong = 1024; // 已初始化全局变量,强符号 __attribute__((weak)) int weak1 = 2222; // 使用标识修饰的弱符号 int main(void) {     printf("编程珠玑\n");     return 0; }

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

同名时,用哪个?

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

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

而第二点也有示例,示例中,虽然定义了两个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字节。

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

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

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯