由于最近都在忙着复习考试,所以自己的读书笔记也就落下了. 现在只剩下最后的单片机了,还有四天时间,现在复习?

算啦,等到最后一天再说吧. ~~额  慢慢的我已经习惯这节奏,喜欢上裸考的心跳~

关于目标文件的相关知识,其实还是蛮多的.我能做到的就是选取自己需要的知识去学习.(其实是自己能理解和在时间

不浪费的情况下去选取值得学习的知识,从大体上去掌握.这可能和研究这些编译链接的细节的最初出发点是相违背的,

最初的出发点是想要弄清楚细节,但是从另外一个角度来思考,重点是编译和链接,对于这其中的小细节,忽略也是

可以接受的).

一、如何引申出符号修饰与函数签名的概念?

小生有仔细的思考过这个问题,但是最后还是选择总结书上的语言,然后引申出这个问题,能力所限,如果您读到这篇

拙文,又不满意的地方请拍砖,小生在这里接受批评教育.   :-)

1.符号修饰与函数签名诞生的背景和条件:

20世纪70年代,编译器编译源代码产生目标文件时,符号与相应的变量和函数的名字是一样的.后来Unix平台和C语言

发明时,已经存在了相当多的使用汇编编写的库和目标文件.这样问题就产生了,一个C程序要使用这些库的话,C语言

中不可以使用这些库中定义的函数和变量的名字作为符号名,否则将会跟现有的目标文件冲突.

为了防止类似的符号名冲突,Unix下的C语言就规定,C语言源代码中的所有全局变量和函数经过编译后,相对应的符号名

前加上下划线"_".而Fortran语言的源代码经过编译以后,所有的符号前后都加上"_".

这种简单而原始的方法的确能够暂时减少多种语言目标文件之间的符号冲突的概率,但是没有从根本上去解决符号冲突的问题.

a. 对不同语言源代码编译后生成的目标文件中添加上不同的符号约束,但是同一种语言的符号冲突问题还是没有解决.

b. 由于模块是协同开发的原因,导致出现的符号冲突概率更大. 如果想要减少冲突,那么就要制定相当复杂和繁琐的编码规范.

而且这些工作在现在看来是无谓的,浪费时间.

就上面这一点,我们是可以验证的.gcc 提供了编译参数"-fleading-underscore"/"-fno-leading-underscore"来开启或者关闭生成下

划线符号.一个简单的HelloWorld.c程序:

#include <stdio.h>
#include <stdlib.h>/// GLOBAL TEST VAR
int global_test_var = 100;/// TEST METHOD
void test_method();int main(int argc, char *argv[])
{test_method();printf ("%s\n","HelloWorld");return EXIT_SUCCESS;
}void test_method()
{printf ("%s\n","TEST METHOD!");return;
}

使用工具readelf可以查看生成的目标文件中的信息.

可以看到确实是是在全局变量和函数方法前面生成了下划线.

2. 名称修饰和函数签名的诞生和C++关系密切:

很多人都知道C++很复杂,拥有很多复杂的机制和特性,有的时候我们会深深的爱上这些机制和特性,有的时候也会让我

们为之头痛.C++有类,继承,虚机制,重载,名称空间等等这些特性,这些特性使符号管理更加复杂.所以后来诞生了符号

修饰和函数签名.至于其中的相关细节,我想这些没必要讨论,其原理是很简单的:

使用名称修饰和函数签名就是为了使避免产生符号冲突.使用一定的机制使源代码中的符号在生成的目标文件中能够保持

唯一性,保证了唯一性也就削弱和消除了冲突的可能性.是不是很简单呢?呵呵,至少原理是很简单的,具体的实现机制应该

是相当复杂的,这里不做猜测.

前面使用readelf工具可以查看目标文件中的内容信息,以及编译后编译器对符号做的变动.那就去验证一下名称修饰和函数

签名的机制.同样还是一个简单的程序:

#include <iostream>namespace sample_namespace
{int sample_var = 10;typedef int sample_int;  class sample_class{

    sample_class(simple_int parm):sample_parm(parm){}int sample_func(int sample_parm1, double sample_parm2);sample_int sample_parm;};
}int main(int argc, char *argv[])
{return 0;
}

这个小程序确实是很简单,下面使用工具来看看生成的目标文件中的信息:

(囧了 发现看不到什么东西...) 不怕,还有其他的工具使用,我们使用objdump.

这里看到在.text节区中_GLOBAL__sub_I__ZN16sample_namespace10sample_varE这个东西,好吧,先不管这是什么东西,下面看看

汇编代码:

好吧,这里就比较的清晰了,下面就来解释一下这个东西: _ZN16sample_namespace10sample_varE

这是名称修饰机制生成的.这样子看起来是不清晰的,不过是可以使用工具去解释的: c++filt _ZN16sample_namespace10sample_varE

结果很简单  其实就是我们的sample_namespace:sample_var.

三、extern "C"

其实extern "C" 是一个关键字,是C++提供兼容C的关键字.

C++编译器会将在extern "C"大括号作用域内的代码都做为C语言处理. 所以相应C++的名称修饰和函数签名机制都不会有作用.

在很多的IDE中,在创建一个源文件的时候都会友好的做好一些基础工作,C与C++兼容的一些代码也会自动生成:

#ifdef _cplusplusextern "C" {#endif// xxxx#ifdef _cpluspus}#endif

这些技巧的使用在很多的库中都有用到,很常见.

既然使用关键字extern "C"修饰的语句在执行的时候都不会经过C++名称修饰的处理,那么假设:

我们了解C++名称修饰的机制.

那么我们可以在代码中尝试加入经过名称修饰处理并且使用extern "C"修饰的语句,那么会怎么样子处理呢?

表述能力有限,举个例子:

就像上面的例子一样,改写一下部分代码:

extern "C" int _ZN16sample_namespace10sample_varE;int main(int argc, char *argv[])
{using namespace std;cout<<_ZN16sample_namespace10sample_varE<<endl;return 0;
}

这种结果会怎么样呢? 在处理的过程中并没有引用命名空间sample_namespace,但是却尝试着去输出其中的变量simple_var.

结果是成功了,成功输出了:10.

到这里就尽我所能的表述完了,总结了一下自己的看书以及查资料的所得. 主要目的是作为自己的总结. 如果您看到这篇文章,

并且能获得一点点收获,小生会很高兴.如果您觉得写的不好,那么就请原谅~~

转载于:https://www.cnblogs.com/respawn/archive/2012/06/30/2571367.html

程序员的自我修养 - 符号修饰 函数签名 以及一个引申的问题: extern c相关推荐

  1. 【读书笔记】【程序员的自我修养 -- 链接、装载与库(三)】函数调用与栈(this指针、返回值传递临时对象构建栈、运行库与多线程、_main函数、系统调用与中断向量表、Win32、可变参数、大小端

    文章目录 前言 介绍 内存 内存布局 栈与调用惯例 堆与内存管理 运行库 入口函数和程序初始化 C/C++运行库 运行库与多线程 C++全局构造与析构 fread 实现 系统调用与API 系统调用介绍 ...

  2. 【读书笔记】【程序员的自我修养 -- 链接、装载与库(二)】进程虚拟地址空间、装载与动态链接、GOT、全局符号表、共享库的组织、DLL、C++与动态链接

    文章目录 前言 介绍 可执行文件的装载与进程 进程虚拟地址空间 装载方式 操作系统对可执行文件的装载 进程虚存空间分布 ELF文件的链接视图和执行视图 堆和栈 Linux 内核装载ELF & ...

  3. 《程序员的自我修养》

    <程序员的自我修养>这本书偏底层,来来回回读了有三四遍了,每一次都有新的收获,不过很快又会忘记,所以写下了这本书从17年12月份至今的全书的笔记,留作以后自己复习. 第二章:编译和链接 源 ...

  4. 程序员的自我修养阅读笔记

    编译和链接 将编译和链接合并到一起的过程称为构建(Build). 从源文件生成最终可执行目标文件共有4个步骤: 预处理(Prepressing) 编译(Compilation) 汇编(Assembly ...

  5. 程序员的自我修养------勘误表

    谢谢你们的辛勤劳动,[程序员的自我修养]真的不错,花一周时间看完后,把以前的东西都串起来了,在看的过程中,发现一些小瑕疵,看到顺便记下,要在以后的版本中修改就更完美了.我购买的是2012年5月第9次印 ...

  6. 《程序员的自我修养》读书总结

    http://www.jianshu.com/p/47156b4259ed 最初买<程序员的自我修养>这本书,只因为在京东买书差一些钱,不够用优惠券.买回来以后的很长一段时间,我都以为这本 ...

  7. 程序员的自我修养--链接、装载与库笔记:总结

    <程序员的自我修养----链接.装载与库>这本书是2009年出版的,书中有些内容的介绍可能已经过时,已不再适用于现在的C/C++开发,而且书中展示的结果均是在32位机上进行的操作,这里全部 ...

  8. 腾讯朋友力荐书籍:程序员的自我修养:链接、装载与库

    后台开发需要学习底层知识,只有底层知识掌握了,学一些中间件是信手捏来,中间件也是跑在底层的操作系统上.<<程序员的自我修养:链接.装载与库>>对学习底层知识非常有帮助,腾讯的朋 ...

  9. 程序员的自我修养—链接、装载与库 笔记

    程序员的自我修养-链接.装载与库 笔记 内存管理 直接使用物理内存地址 虚拟内存-分段 虚拟内存-分页 分页和分段的主要区别 段页式 代码生成过程 预处理 编译 词法分析 语法分析 语义分析 源代码优 ...

  10. 从实践理解《程序员的自我修养》(1)

    从实践理解<程序员的自我修养>(1) 前言 这篇文档主要从实践的角度充分理解<程序员的自我修养>一书中提到的细节.书中提到的各种机制.数据结构,我都将在实际系统中找到并理解它们 ...

最新文章

  1. R语言使用compareGroups包compareGroups函数生成表统计表、createTable函数创建二元表、并导出结果到文档(doc、csv、xlsx、pdf)
  2. pythonexcelweb交互插件_来一次Python与Excel的完美交互
  3. 2021年1月19日工作日志 - Cypress regression tests build error
  4. 装windows和Linux系统时找不到硬盘,pe安装系统没有出现磁盘,不能识别磁盘
  5. mysql 日期和时间函数_介绍一下mysql的日期和时间函数
  6. UFIDL稀疏自编码代码实现及解释
  7. 由浅至深 谈谈.NET混淆原理(三)-- 流程混淆
  8. 大数据之-Hadoop源码编译_源码编译具体流程_以及编译步骤---大数据之hadoop工作笔记0046
  9. yaf mysql pdo 封装_PDO 操作数据库
  10. centos 5开机出现PCI错误:Not using MMCONFIG
  11. 【python】《多媒体技术与应用》实验报告「数字图像基础」
  12. redis可视化工具desktop manager
  13. git push 报错 pre-receive hook declined
  14. 在gitee码云上搭建一个网站
  15. Django-bootstrap3插件搭建Django+Bootstrap网站
  16. 我的世界服务器怎么做无限的弓,我的世界制作无限弓流程介绍
  17. 第三方框架Masonry的基本使用
  18. R或RStudio下载包时出错解决方案
  19. Clion~Clion常用配置和插件
  20. MapX.h和MapX.cpp下载

热门文章

  1. sql执行遇到汉字会停止执行吗_(数据)产品经理应该学会的SQL优化和进阶技巧...
  2. python注册登录代码_python基础--注册和登录功能 代码
  3. Linux与Xshell:登陆服务器与后台执行程序
  4. 计算机专业基础 -- Java语言相关基础知识
  5. unity linux桌面环境,现在仍然可以在Ubuntu 20.04上安装Unity桌面环境
  6. Keras实现text classification文本二分类
  7. mysql表空间查看及创建
  8. 康托展开逆展开算法笔记
  9. JS中的拖动之—— ondragstart,ondrag,ondragend , ondragenter , ondragover , ondragleave, ondrop 的区别...
  10. HDU 2063 过山车