extern"C"详解

与世无争的帅哥 提交于 2020-01-25 16:50:33

我们一般在 c++ 中使用 c 语言的库时,都会引用 c 库的头文件。例如string.hc库头文件中我们经常会看到这样的代码。

#ifdef __cplusplus
    extern "C"{
#endif

......

#ifdef __cplusplus
    }
#endif

__cplusplus 定义着 c++ 编译器的版本,如果没有定义则表示当前编译器不是 c++
上述代码的意思是如果编译代码的是 c++ 编译器,那么就将中间包含的内容以 c 语言的语法编译,为什么要这么做呢,下面我举个例子

add.h

#ifndef _ADD_H
#define _ADD_H

int add(int a, int b);

#endif // _ADD_H

add.c

int add(int a, int b)
{
    return a + b;
}

main.cpp

#include <iostream>
#include "add.h"

using namespace std;

int main(int argc, char *argv[])
{
    cout << add(3, 5) << endl;
    return 0;
}

执行编译

g++ main.cpp add.c -o main

这样的编译是没问题的,因为我们用g++编译了所有文件,都按照c++的编译规则。

那么如果add.cc库的形式或者是用gcc编译的二进制文件呢?

g++ main.cpp add.o -o main
/tmp/ccGrFT1M.o:在函数‘main’中:
main.cpp:(.text+0xf):对‘add(int, int)’未定义的引用
collect2: error: ld returned 1 exit status

编译器告诉我说没有 add 这个函数的引用,但是在add.c里面明明定义了,为什么说没有呢。

这就要从c++c语言对函数编译时的区别说起了,c++函数编译时因为有重载的语法,为了使每个函数在编译期都能绑定到唯一的函数,会将每个函数都进行重命名,比如上面的add就会编译成_add_int_int这样的符号。
main.cpp 文件中包含了 add.h,编译时就会将 add 函数编译成 _add_int_int 然后链接,而使用gcc编译的add.o,就会将add函数只编译成_add, 所以g++在链接时就说找不到引用。

解决办法是将c头文件中加入

#ifdef __cplusplus
    extern "C"{
#endif

int add(int a, int b);

#ifdef __cplusplus
    }
#endif

这样在extern "C"{}中包裹的函数都会按照c编译器的方式去编译,只会编译出 _add 这样的函数符号,这样在链接过程中才可以正确的找到和库中对应的函数。

_add_int_int 只是一种命名方式,只要能解决重载函数的唯一性问题都可以,这就要看不同的编译器如何实现了
:可以看一下c库的头文件(stdio.h等),都有这样的代码,为了保证c++程序可以正确调用c库中的函数

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!