目录
前言
本文使用的使用的语法符合c++标准,把.h.c.cpp文件拷贝到微软的vs下和xcode下都能运行.demo中的代码是在xcode平台编写.,截图的汇编指令也是arm芯片的汇编
首先看一下我们要做测试的主函数
//
// main.cpp
// externC_ifndef_define_endif_pragma onceDemo
//
// Created by 谭迪文 on 2021/6/30.
//
#include <iostream>
#include "calculator.h"
#include "div.hpp"
using namespace::std;
int mul(int a,int b);
int main(int argc, const char * argv[]) {
// insert code here...
int result = sum(1,2); //调用c函数
result = sub(3, 1); //调用c函数
result = mul(2, 3); //调用c++函数
result = division(2, 1);//调用c++函数
return 0;
}
int mul(int a,int b){
return a*b;
}
extern "C"详解
上面调用的函数sum ,sub都是c语言的函数,定义在.c文件中,之所以能被main.cpp文件使用,就是因为在.h的头文件中,使用了extern “C”,这个只能在.cpp文件中被编译器识别,如果写在.c文件中,就会报错,无法识别extern “C”.所以如果代码想要被c++文件和 c文件同时使用,就必须用到条件编译 #ifdef __cplusplus,这个我们一会再说,先记着. 当cpp文件中遇到 extern “C” 以后,会把后面的代码,或者 后面{ }大括号中的代码,按照c语言进行编译,这样,就不会给里面的代码,如果是函数起别名,根据编译器不同,起名字也不一样,例如,xcode平台里面的用的arm汇编,cpp编译器就会把函数名前面加下划线_进行寻找函数.例如 sum会按照_sum来起名,如下图:
如果不加extern “C”,那么cpp文件,默认会把sum当做c++函数来看,就会不会寻找_sum,就会找不到,为了做对比,mul和 division这2个是c++的函数,看图中分别被重命名为:__Z3mulii 和 __Z8divisionii ,按照这个规律 sum的c++函数应该被重命名为: __Z数字函数名字ii, 因为数字的规律不知道,加入数字是1,sum就被重命名为:__Z1sumii ,但是没找到__Z1sumii ,编译器就会报错,说找不到函数sum.如果加了extern “C”,编译器就会去按照c语言函数规则去寻找函数sum,寻找_sum.这样就找到了
关于.h中的完整代码一会在放出,先看一下#ifdef __cplusplus的讲解,否则容易理解不了
#ifdef 和 #ifndef 和 #enfif
#ifdef 意思是:判断是否定义了 后面你的内容,例如#ifdef ABC,就是判断是否宏定义了 ABC ,如果上面有#define ABC,就执行#ifdef后面的内容
#ifndef意思是:判断如果上面没有定义某个内容,例如 #ndef ABC,就是判断如果上面,没有#define ABC,则执行 #ifndef后面的内容,这2个后面都要以 #endif结尾.
#ifdef __cplusplus
#ifdef __cplusplus 的意思是 判断 当前代码,是否 执行执行过#define __cplusplus,就是当前文件是否定义过 __cplusplus.如果是cpp文件,里面默认有一个隐藏的#deinfe __cplusplus,当这段代码被c++文件包含的时候,就会发现真的定义了 __cplusplus,然后执行后面代码,后面代码是:extern "C’,执行结果就是,当被cpp文件包含的时候,就执行extern “C”. 如果被.c文件包含,就不会执行extern “C”,因为 .c文件无法识别 extern "C"语法,编译会报错.组合起来使用就是:
#ifdef __cplusplus
extern "C"{
#endif
int sum(int a,int b);
int sub(int a,int b);
#ifdef __cplusplus
} //__cplusplus
#endif
上面的代码被cpp包含以后就会变成如下,作用是用c语言方法编译函数sum和 sub ,那么编译器会查找_sum和 _sub:
extern "C"{
int sum(int a,int b);
int sub(int a,int b);
}
如果被.c文件包含,就会什么都没有.看下.h文件中的完整写法加注释:
//
// calculator.h
// externC_ifndef_define_endif_pragma onceDemo
//
// Created by 谭迪文 on 2021/6/30.
//
#ifndef calculator_h
#define calculator_h
#include <stdio.h>
/*
extern "C"{ //如果去掉#ifdef __cplusplus,这样会报错,因为这个.h文件被calculator.c包含了,.c文件不能识别extern "C",extern "C"是c++语法
}
*/
#ifdef __cplusplus
extern "C"{ //被#ifdef __cplusplus 包含以后,可以正常编译的原因是,如果是.c文件,.c文件里面默认不会#define __cplusplus ,就不会把extern "C"包含到.c文件中
//.cpp文件默认是会隐藏包含代码#define __cplusplus ,包含这段代码以后,遇到#ifdef __cplusplus,会执行{}里面的extern "C",这样会把函数sum按照c语言的方法编译,c++文件里面调用sum的时候,就会去查找c语言编译的sum,而不是c++编译的sum,因为c++编译函数的时候会把函数进行重命名,在查找c++的sum的时候,发现没找到,就会报错,没找到sum,但是加了extern "C"以后,c++文件里面包含了本头文件,并且执行到这段代码,就会知道不去寻找c++编译的sum,而是去寻找c语言编译的sum
#endif
int sum(int a,int b);
int sub(int a,int b);
#ifdef __cplusplus
} //__cplusplus
#endif
#endif /* calculator_h */
extern "C"{
int sum(int a,int b);
int sub(int a,int b);
}
看下.c文件中的函数定义,因为在.h中的extern “C” 被 #ifdef __cplusplus 和 #endif 包住,所以在.c文件中不会执行 extern “C”,所以编译不会报错:
//
// calculator.c
// externC_ifndef_define_endif_pragma onceDemo
//
// Created by 谭迪文 on 2021/6/30.
//
#include "calculator.h"
int sum(int a,int b){
return a+b;
}
int sub(int a,int b){
return a-b;
}