打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
探秘!编译器眼中不一样的变量名

我们在使用C语言或C++时,常用的变量定义范围有全局全局变量、全局静态变量、局部静态变量、函数内部局部变量等,我们也知道函数内部局部变量和全局变量重名、函数内部静态变量和全局静态变量重名时,都是使用的函数内部声明变量,那么编译器是如何做到的呢?

这就要从编译过程开始说起了....

编译过程

图片来自网络

图片来自网络

测试代码

#include <iostream>using namespace std;int G_a = 0;int G_b;static int s_c=1;static int s_d;int fun(){ static int s_c=2; int G_b=2; static int s_e=2; int in_a = s_e++; return in_a;}int main() { int m_b = fun(); cout<<'m_b= '<<m_b<<endl; m_b = fun(); cout<<'m_b= '<<m_b<<endl; G_b=3; return 0;}

编译操作

①Preprocessor(预处理):

处理一些#号定义的命令或语句(如#define、#include、#ifdef等),生成.i文件。

$ g++ -o test_variable.i -E test_variable.cpp

②Compiler(编译)

进行词法分析、语法分析和语义分析等,生成.s的汇编文件

$ g++ -o test_variable.s -S test_variable.i

③Assembler(汇编)

将对应的汇编指令翻译成机器指令,生成二进制.o目标文件

$ g++ -o test_variable.o -c test_variable.s

④Linker(链接)

  • 动态链接:

在链接期,只在可执行程序中记录与动态链接库中共享对象的映射信息。在程序执行时,动态链接库的全部内容被映射到该进程的虚拟地址空间。其本质就是将链接的过程推迟到运行时处理。

  • 静态链接:

在链接期,将静态链接库中的内容直接装填到可执行程序中。在程序执行时,这些代码都会被装入该进程的虚拟地址空间中。

$ g++ -o test_variable -c test_variable.o

编译后的中间文件解析

*.i文件:

预编译时,把引用的头文件内容和当前对应cpp代码拷贝进来,并把名空间等进行展开,打开或关闭对应的编译宏。

*.s文件:

进行词法分析、语法分析和语义分析等,生成.s的汇编文件。此时会把变量和函数等根据是否全局、静态类型等命名成不冲突的其他名称。

从生成的文件可以看出来,初始化的全局变量、未初始化的全局变量、全局静态变量、局部静态变量、静态函数等,名称都是按照编译器的规则进行了原样保持或添加了其他字符做唯一标识。编译器这么做的原因,就是为了保证符号唯一性,从而能对应上编译出的静态地址。

备注:变量名在运行时不存在,它们在编译期间被丢弃。但是,编译器可能会发出存储在应用程序二进制文件中的调试信息,以允许开发人员调试应用程序.但是,这通常会在发布版(Release版本会去除-g信息或通过strip去除符号信息)中删除。

使用nm命令查看可执行文件内部的符号信息

*.o文件:

将对应的汇编指令翻译成机器指令,生成二进制.o目标文件。咱们用文本文件打开查看是乱码,但是可以通过https://gcc.godbolt.org/工具在线查看汇编代码。

总结

虽然我们在写代码时,编译器会自动帮我们做一些工作,平时多了解一些编译器内部实现原理,对我们的编码质量和编码效率提升还是很有帮助的。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
变量的声明与定义以及关键字extern的用法
C语言中关键字auto、static、register、const、volatile、ex...
自动变量与非自动变量(Non-automatic variables)
C语言中的作用域和生命周期
变量的作用域和储存类型
C++ 基础知识和基本语法串讲
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服