美文网首页
extern "C"

extern "C"

作者: cj3479 | 来源:发表于2020-01-30 01:15 被阅读0次

extern "C"指示编译器这段代码按照c的方式编译,猛然看到这句话会感觉到很懵逼,下面我们来看看extern "C"出现的背景
对比下C++ C ObjectC三种语言发现
C++支持重载
比如可以这样
void testA() {
printf("%d", a);
}
void testA(int a) {
printf("%d", a);
}

C不支持支持重载
void testA() {
printf("%d", a);
}
void testA(int a) {
printf("%d", a);
}
编译会出现redefinition of 'test'

OC
@implementation ViewController

  • (void)test:(int)a{
    }
  • (void)test:(NSString*)a{
    }
    @end
    编译会出现Duplicate declaration of method 'test:'
    注意在OC中方法名如果带参数的话,会加上":"
    如果是下面两个方法,
  • (void)test:(int)a
  • (void)test
    没问题,一个是test: 一个是test

所以在C++中,编译器会将方法void test()和void test(int a);编译成这样的符号
(使用nm -m 目标文件路径)
0000000000000030 (__TEXT,__text) external __Z5testAi
0000000000000000 (__TEXT,__text) external __Z5testAv
这个i和v表示参数是int和void类型,返回值没有体现出来,这个说明两个方法如果返回值不一样,其他都一样的话,也只是一个方法,不能共存的

在看看C中的方法void test(int a);编译之后成什么样子
0000000000000030 (__TEXT,__text) external _testA
仅仅是个testA,参数和返回值没有体现,这侧面跟C的不能重载特性相匹配

在看看OC中的方法 (void)test:(int)a编译之后成什么样子
0000000000000210 (__TEXT,__text) non-external -[ViewController test:]
同C语言

那如果C++直接调用C中的方法会出现什么问题呢
比如
ModuleA是用C写的,代码如下
TestModuleA.h

ifndef TESTC___TESTMODULEA_H

define TESTC___TESTMODULEA_H

int testFun(int, int);//声明

endif //TESTC___TESTMODULEA_H

TestModuleA.c
int testFun(int a, int b){//定义
return a+b;
}

main是用C++写的,代码如下
main.cpp

include <iostream>

include "TestModuleA.h"

using namespace std;
int main() {
cout << testFun(2, 3) << endl;
}
那么运行时(链接阶段,寻找符号)会出现以下错误
[ 50%] Linking CXX executable TestC__
Undefined symbols for architecture x86_64:
"testFun(int, int)", referenced from:
_main in main.cpp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

其实就是找不到testFun(int, int)这个符号,为什么呢

那我们首先看看main的符号表,
(undefined) external __Z7testFunii
undefined表示不在main定义,但是在main中使用的方法,它的符号是__Z7testFunii,其实就是跟 "testFun(int, int)"对应,ii表示int,int

再看看TestModuleA的符号表
TestModuleA
nm -m TestModuleA.o
0000000000000000 (__TEXT,__text) external _testFun
testFun的方法对应的符号是_testFun,

这样看来就很明显,需要的跟实际的符号不匹配,所以找不到符号

那么怎么解决呢?
extern "C"应运而生
再来回顾下它的含义
让被作用的代码块采用c语言的编译规则编译
修改下TestModuleA.h的代码如下

ifndef TESTC___TESTMODULEA_H

define TESTC___TESTMODULEA_H

ifdef __cplusplus //而这一部分就是告诉编译器,如果定义了__cplusplus(即如果是cpp文件,

extern "C"{ //因为cpp文件默认定义了该宏),则采用C语言方式进行编译

endif

int testFun(int, int);

ifdef __cplusplus

}

endif

翻译一下当一个Cpp文件引入TestModuleA.h,它就变成

ifndef TESTC___TESTMODULEA_H

define TESTC___TESTMODULEA_H

extern "C"{
int testFun(int, int);
}

endif

这样的话,当cpp文件编译的时候发现extern "C"的时候,它就会按照C的方式寻找符号,即寻找_testFun这个符号,不信,
你再看看重新编译之后的main.o的符号表
(undefined) external _testFun

同理如果在C++里面有这样一段代码
extern "C"{
void testfunAAAa(int a);
}
void testfunAAAa(int a){

}
那么它的符号表是这样的
0000000000000000 (__TEXT,__text) external _testfunAAAa
这样的话,C就可以调用C++的方法了,

同理如果OC想调用C++代码的话,可以使用extern "C"
也可以将OC的文件后缀改为mm,mm兼容c++的编译方式,查找符号时
按照C++的方式查找,但是mm里面如果有调用C方法时,那就会找不到C里面的符号,因为它是按照c++的方式查找到,这时也可以使用extern "C"解决问题

个人理解,extern "C"有两层意思,
1.寻找方法符号的时候,按照C的规则寻找
2.编译方法的时候,按照C的规则编译,生成C的命名规范

相关文章

网友评论

      本文标题:extern "C"

      本文链接:https://www.haomeiwen.com/subject/mzcbthtx.html