博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Extern "C"
阅读量:7109 次
发布时间:2019-06-28

本文共 1274 字,大约阅读时间需要 4 分钟。

未加extern “C”声明时的编译方式
  首先看看C++中对类似C的函数是怎样编译的。
  作为一种 的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为:
  void foo( int x, int y );

  该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangledname”)。_foo_int_int这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的

例如,在C++中,函数void foo( int x, int y )与void foo( int x, float y)编译生成的符号是不相同的,后者为_foo_int_float。

  同样地,C++中的变量除支持 外,还支持类成员变量和全局变量。用户所编写程序的类成员变量可能与全局变量同名,我们以"."来区分。而本质上,编译器在进行编译时,与函数的处理相似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全局变量名字不同。
  未加extern "C"声明时的连接方式
  假设在C++中,模块A的头文件如下:
  // 模块A头文件 moduleA.h
  #ifndef MODULE_A_H
  #define MODULE_A_H
  int foo( int x, int y );
  #endif
  在模块B中引用该函数:
  // 模块B实现文件 moduleB.cpp
  #include "moduleA.h"
  foo(2,3);
  实际上,在连接阶段,连接器会从模块A生成的目标文件moduleA.obj中寻找_foo_int_int这样的符号!
  加extern "C"声明后的编译和连接方式
  加extern "C"声明后,模块A的头文件变为:
  // 模块A头文件 moduleA.h
  #ifndef MODULE_A_H
  #define MODULE_A_H
  extern "C" int foo( int x, int y );
  #endif
  在模块B的实现文件中仍然调用foo( 2,3 ),其结果是:
  (1)模块A编译生成foo的目标代码时,没有对其名字进行特殊处理,采用了C语言的方式;
  (2)连接器在为模块B的目标代码寻找foo(2,3)调用时,寻找的是未经修改的符号名_foo。
  
如果在模块A中函数声明了foo为extern "C"类型,而模块B中包含的是extern int foo( int x, int y ) ,则模块B找不到模块A中的函数;反之亦然。
  

转载于:https://www.cnblogs.com/lovemo1314/archive/2011/10/24/2222316.html

你可能感兴趣的文章
【RxSwift 实践系列 1/3】为什么使用RxSwift
查看>>
Plasma进展受阻,社区开始推崇Snarks技术
查看>>
iOS逆向之旅(基础篇) — 汇编(四) — 汇编下的函数
查看>>
学习OpenGL ES之绘制更多的图形
查看>>
强大的 VS Code
查看>>
利用SimpleMDE打造类似简书、掘金的markdown编辑器
查看>>
清除浮动的几种方法
查看>>
js比较操作符 结果是Boolean值?
查看>>
Nashorn-ActionContext
查看>>
正则表达式入门教程
查看>>
CDN介绍及使用入门
查看>>
不输给MacBook的win10精确式触摸板
查看>>
自定义数组原型对象方法
查看>>
[译]KVC 和 KVO详解
查看>>
Java实现终止线程池中正在运行的定时任务
查看>>
iOS计步器实例
查看>>
Spring Cloud Netflix
查看>>
这应该是你们想要的 DOS 命令
查看>>
数组map vs foreach,及map、fliter、reduce的链式调用
查看>>
使用 Grid 进行常见布局
查看>>