欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

在C++编译器下,将代码按照C语言编译

发布时间:2024/1/1 63 豆豆
生活随笔 收集整理的这篇文章主要介绍了 在C++编译器下,将代码按照C语言编译 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

extern "C"的使用

  • 一、定义-defintion
  • 二、extern "C"使用举例-example
  • 三、extern "C"的用武之处在哪?
  • 四、extern "C"常用特性
    • 1.C++调用第三方库(含.h&.c文件)
    • 2. C语言也调用第三方库(含.h&.c文件)
      • a. #define __cplusplus解释
      • b. #ifdef条件编译
      • c. 启示
  • 五、不相关学习tips
    • 1.防止某个.h文件被重复include
    • 2.防止某个.h文件被重复include(#pragma)

一、定义-defintion

被extern "C"修饰的代码会按照C语言的方式去编译

二、extern "C"使用举例-example

我们都知道,C语言不支持函数重载,只有C++才支持函数重载。下方两个函数就会按照C语言进行编译,由于是重载函数,所以会报错

extern "C" void function(int v1, double v2) {cout << "int v1, double v2" << endl; } extern "C" void function(double v1, int v2) {cout << "double v1, int v2" << endl; }int main(int argc, char **argv) {function(10,10.0);//会报错,因为C语言不支持函数重载getchar();return 0; }

三、extern "C"的用武之处在哪?

  • 由于C、C++编译方式的不同,这种机制往往用在C\C++混合开发,往往做项目时,可能会用到第三方库:这个库可能是C语言写的,这时候这种机制就很重要。
第三方库math.c文件,提供了一个函数,但用的C语言写的 int sum(int v1,int v2) {return v1 + v2; } my.cpp自己的cpp工程文件,想要调用math.c里的函数为我所用int sum(int v1,int v2);//声明一下 //C++编译器一看到这个函数,可能就直接name manuling了,改成了sum_i_iint main() {sum(1,1);getchar();return 0; } //这时候就会出错,因为C语言编译规则和C++编译规则不相同。可能C++看到sum的函数声明,直接把名字改成sum_i_i,而C语言中的名字就是sum,所以C++编译器就会找不到函数,就会报错。
  • 我还是想要用第三方库里的函数,怎么办呢?这时候就要借助extern “C”
第三方库math.c文件,提供了一个函数,但用的C语言写的 int sum(int v1,int v2) {return v1 + v2; } my.cpp自己的cpp工程文件,想要调用math.c里的函数为我所用extern "C" int sum(int v1,int v2);//声明一下 //这里我要告诉C++编译器,这个函数是C语言编译的,你不要乱改名字了。如此,就可以实现C++环境调用C语言里的东西int main() {sum(1,1);//2getchar();return 0; }

四、extern "C"常用特性

1.C++调用第三方库(含.h&.c文件)

函数如果同时有声明(.h文件)和实现(.c),extern “C"修饰只放在函数声明中,即.c文件实现函数时,可以不用再次修饰。如果.cpp文件引用.h中的C语言函数时:如果.h的函数已经被extern “C"修饰,则直接#include””;如果没有被修饰,则必须extern “C” #include""

  • .h头文件中的函数声明没有被extern "C"修饰
AAA.h文件 void func_c();//声明时不用extern "C"修饰,那#include时就要用extern "C"修饰 AAA.c文件 void func_c()//实现 {//函数体 } AAA.cpp文件 extern "C" #include"AAA.h"//由于AAA.h文件中的函数没有被extern "C" 修饰,所以想要这个函数按照C语言编译,就必须将include转换。int main() {func_c();getchar();return 0; }
  • .h头文件中的函数声明有被extern "C"修饰
AAA.h文件 extern "C" void func_c();//声明时用extern "C"修饰,那#include时就不用extern "C"修饰 AAA.c文件 void func_c()//实现 {//函数体 } AAA.cpp文件 #include"AAA.h"//由于AAA.h文件中的函数有被extern "C" 修饰,因此这里直接include就可以int main() {func_c();getchar();return 0; }

有函数声明和实现时,想要某个函数采用C语言编译,最好只在函数声明前采用extern “C” 修饰,在函数实现前不做任何操作

2. C语言也调用第三方库(含.h&.c文件)

由于整个项目C++需要调用第三方库(第三方库是用C语言写的),所以用extern “C” 修饰一下这个第三方库里的函数,即可被C++调用。但,我这个项目里如果有.c文件也需要调用这个第三方库,可以直接调用吗?答案是不能的,因为这个第三方库函数已经被extern “C” 修饰了,而C语言是不认识extern “C” 的。

我希望这个第三方库更加的灵活,即C++调用函数时自动加上extern “C” 修饰;C语言调用,extern “C” 自动去掉

a. #define __cplusplus解释

#define __cplusplus这个宏被默认的编写在C++文件的最开头,用来确认这个文件是cpp文件。只要你是cpp文件,第一行编译器默认给你写了一句#define __cplusplus。

b. #ifdef条件编译

#ifdef 和 #endif // 组合使用,达到条件编译的目的。下方代码的最终结果就是:如果某个cpp文件调用这段代码,才会编译代码段,c文件调用这段代码,不会编译这段代码段,即只读到了一对注释

#ifdef __cplusplus //被编译的代码段,如果定义了名为__cplusplus的宏,这段代码段才会被编译,否则会被编译器视为注释 #endif // __cplusplus
  • 于是第三方库的完美写法是这样的:
AAA.h文件 #ifdef __cplusplus extern "C" { #endif // __cplusplusvoid func_c();//声明时用extern "C"修饰,那#include时就不用extern "C"修饰#ifdef __cplusplus } #endif // __cplusplus AAA.c文件 void func_c()//实现 {//函数体 } AAA.cpp文件 #include"AAA.h"//由于AAA.h文件中的函数有被extern "C" 修饰,因此这里直接include就可以 因为是c++环境,所以AAA.h里的代码是这样的:extern "C" {void func_c();//因为C++环境在此之前定义了宏 __cplusplus,所以extern "C"代码被编译保存了下来}int main() {func_c();getchar();return 0; } other.c文件,也需要调用第三方库AAA.h里的函数 #include"AAA.h" //因为是c语言环境,所以AAA.h里的代码是这样的://extern "C" {void func_c();//} //这是因为.C文件里的最开始没有宏定义 __cplusplus int main() {func_c();getchar();return 0; }

c. 启示

以后凡是用C语言编写的第三方库,最好都要按照下述代码改动.h文件。这样的话,C++和C语言文件都可以调用这个第三方库,不仅不会出错,还会使得代码更加规范

//第三方C语言库 #ifdef __cplusplus extern "C" { #endif // __cplusplusvoid function1(); void function2(); void function3(); void function4(); void function5(); ..... #ifdef __cplusplus } #endif // __cplusplus

五、不相关学习tips

1.防止某个.h文件被重复include

我们在开发的时候,当代码量很大时,我们可能会在中间include头文件,下面的组合会解决这个问题
#ifndef BBB
#define BBB
…BBB.h头文件代码
#endif //!BBB

  • 错误示例
BBB.h文件 //代码 某个.cpp文件 #include<BBB.h> ... 可能有很多行代码 ...#include<BBB.h>//我在某处又引入了这个头文件,这时候就会报错,因为我重复包含了.h文件 ...
  • 正确且规范的编写.h头文件。
BBB.h文件 #ifndef BBB //如果没有定义BBB这个宏 #define BBB //定义BBB这个宏,然后下面代码参与编译//代码#endif //!BBB

#include<BBB.h>就相当于把BBB.h文件中的代码全部拷贝一份

某个.cpp文件 #include<BBB.h> //#ifndef BBB //如果没有定义BBB这个宏 //#define BBB //定义BBB这个宏,然后下面代码参与编译代码//#endif //!BBB ... 可能有很多行代码,然后我忘了前面已经#include<BBB.h>了,我又包含了一遍 ...#include<BBB.h>//我在某处又引入了这个头文件,这时候就会报错,因为我重复包含了.h文件 //#ifndef BBB //如果没有定义BBB这个宏,直接判断失败,因为上面已经#define BBB了一次,所以在#endif //!BBB之前的代码都不会编译了 //#define BBB //定义BBB这个宏,然后下面代码参与编译代码//#endif //!BBB ...

2.防止某个.h文件被重复include(#pragma)

新建.h头文件时第一行出现的 #pragma once,是为了防止这个.h文件被重复包含,即也是防止cpp文件中多次包含相同的.h文件。#pragma once可以起到和上述相同的作用

#pragma once 会被定义在.h文件的开头,也会起到防止被重复include的错误。但与上面的#ifndef的区别是什么呢?

#pragma once 和 #ifndef + #define + #endif //! 的区别在于,后者什么编译器都支持,而前者则必须保证GCC3.4版本之后的编译器才支持。同时前者只能针对整个头文件,而后者可以针对文件中的部分代码。

总结

以上是生活随笔为你收集整理的在C++编译器下,将代码按照C语言编译的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。