为什么C编译器在外部名称上加下划线?

我一直在C中工作了很长时间,编译器通常会在extern的开始处加上一个下划线这一事实才被理解……然而, 今天的另一个SO问题让我想知道为什么添加下划线的真正原因。 一篇维基百科文章声称,原因是:

C编译器通常会在所有外部作用域程序标识符前面加下划线,以避免与运行时语言支持的影响相冲突

我认为至less有一个真理的核心,但似乎也没有真正回答这个问题,因为如果下划线被添加到所有的外部实体,它将不会帮助防止冲突。

有没有人有关于领导下划线的理由的良好信息?

Unix creat()系统调用不是以'e'结尾的原因是否增加了下划线部分? 我听说一些平台上的早期连接器对名称有6个字符的限制。 如果是这样的话,那么对外部名称加下划线似乎是一个彻头彻尾的疯狂的想法(现在我只有5个angular色可以玩…)。

C编译器通常会在所有外部作用域程序标识符前面加下划线,以避免与运行时语言支持的影响相冲突

如果运行时支持是由编译器提供的,那么您可能会认为在运行时支持中预先给一些外部标识符加下划线会更有意义!

当C编译器第一次出现时,在这些平台上用C语言编程的基本替代方法是用汇编语言进行编程,并且偶尔还是有用的,用汇编程序和C编写的目标文件是连接在一起的。下划线添加到外部C标识符是为了避免与您自己的汇编代码中的标识符冲突。

(另请参阅GCC的asm标签扩展 ;注意这个前置的下划线可以被看作是一个简单的名称修饰forms,更复杂的语言如C ++使用更复杂的名称修饰,但这是它开始的地方。

如果c编译器总是在每个符号之前加上一个下划线,那么启动/ c运行时代码(通常用汇编语言编写)可以安全地使用不以下划线开头的标签和符号(例如符号'start “)。

即使您在c代码中编写了一个start()函数,它也会在object / asm输出中生成为_start。 (请注意,在这种情况下,c代码不可能生成不以下划线开头的符号),所以启动编码器不必担心为每个符号发明不明显的不可能符号(如$ _dontuse42%$)他/她的全局variables/标签。

所以链接器不会抱怨名称冲突,程序员很高兴。 🙂

以下是不同于编译器在其输出格式中预先加下划线的做法。

这种做法后来被编纂为C和C ++语言标准的一部分,其中使用领先的下划线被保留用于执行。

这是一个惯例,对于c系统库和其他系统组件。 (以及诸如__FILE__之类的东西)。

(请注意,这样的符号(例如:_time)可能导致生成的输出中有2个前导下划线(__time)

从我总是听到的是避免命名冲突。 不是其他的外部variables,但更多的是,当你使用一个库时,它将不会与用户代码variables名冲突。

主要function不是可执行文件的真正入口点。 一些静态链接文件具有最终调用main的真正入口点,而那些静态链接文件拥有不以下划线开头的名称空间。 在我的系统上,在/ usr / lib中,有gcrt1.o,crt1.o和dylib1.o等等。 每个人都有一个“开始”function没有下划线,最终将调用“_main”入口点。 除了这些文件以外的其他东西都有外部的范围 历史与混合汇编程序和C在一个项目中,所有C被认为是外部的。

维基百科 :

C编译器通常会在所有外部作用域程序标识符前面加下划线,以避免与运行时语言支持的影响相冲突。 此外,当C / C ++编译器需要在外部链接中引入名称作为翻译过程的一部分时,这些名称通常以多个前导或尾部下划线的组合来区分。

这种做法后来被编纂为C和C ++语言标准的一部分,其中使用领先的下划线被保留用于执行。