c++中extern “C“的作用及理解

1 意图

extern "C"是C++特有的指令(C无法使用该指令),目的在于支持C++与C混合编程。

2 作用

extern “C”的作用是告诉C++编译器用C规则编译指定的代码(除函数重载外,extern “C”不影响C++其他特性)。

3 原因

为什么要用C规则编译C++代码呢?

因为C和C++的编译规则不一样,主要区别体现在编译期间生成函数符号的规则不一致。

C++比C出道晚,但是增加了很多优秀的功能,函数重载就是其中之一。由于C++需要支持重载,单纯的函数名无法区分出具体的函数,所以在编译阶段就需要将形参列表作为附加项增加到函数符号中。如以下代码

void Function(int a, int b)
{
    printf("Hello!!! a = %d, b = %d\n", a, b);
}

C和C++对应的的汇编码如下

  • C汇编结果
...
Function:
.LFB11:
    .cfi_startproc
    movl    %esi, %edx
    xorl    %eax, %eax
    movl    %edi, %esi
    movl    $.LC0, %edi
    jmp    printf
    .cfi_endproc
...
  • C++汇编结果
...
_Z8Functionii:
.LFB12:
    .cfi_startproc
    movl    %esi, %edx
    xorl    %eax, %eax
    movl    %edi, %esi
    movl    $.LC0, %edi
    jmp    printf
    .cfi_endproc
...

容易发现,两段代码的区别仅在于函数 Function(int a, int b) 编译后对应的符号不同

  • C:Function

  • C++_Z8Functionii

C++编出来的函数符号明显比C的多出了一些信息(如ii),这里多出来的后缀信息就是形参列表的参数类型信息。

好,C和C++编译规则对编译期间产生函数符号的影响我们知道了,但这又有什么用呢?

别急,很多人可能都遇到类似过这样的情况

/* MyFunction.c */
void Function(int a, int b)
{
    printf("Hello!!! a = %d, b = %d\n", a, b);
}


/* main,cpp */
extern void Function(int a, int b);

int main()
{
    Function(1, 2);
}

C提供写了一个函数,用C++代码调用该函数,看起来没什么问题,但是编译的时候...

/tmp/ccbkGl1J.o:在函数‘main’中:
main.cpp:(.text.startup+0xf):对‘Function(int, int)’未定义的引用
collect2: 错误:ld 返回 1

找不到对Function(int, int)的定义?怎么可能?

如果找到就玄幻了,大家注意观察,错误出在哪一步?对,编译阶段没报错,是链接的阶段报错了。我们来看看两个文件的汇编结果

    .file    "MyFunction.c"
    .section    .rodata.str1.1,"aMS",@progbits,1
.LC0:
    .string    "Hello!!! a = %d, b = %d\n"
    .text
    .p2align 4,,15
    .globl    Function
    .type    Function, @function
Function:
.LFB11:
    .cfi_startproc
    movl    %esi, %edx
    xorl    %eax, %eax
    movl    %edi, %esi
    movl    $.LC0, %edi
    jmp    printf
    .cfi_endproc
.LFE11:
    .size    Function, .-Function
    .ident    "GCC: (GNU) 6.4.1 20170727 (Red Hat 6.4.1-1)"
    .section    .note.GNU-stack,"",@progbits
    .file    "main.cpp"
    .section    .text.startup,"ax",@progbits
    .p2align 4,,15
    .globl    main
    .type    main, @function
main:
.LFB0:
    .cfi_startproc
    subq    $8, %rsp
    .cfi_def_cfa_offset 16
    movl    $2, %esi
    movl    $1, %edi
    call    _Z8Functionii
    xorl    %eax, %eax
    addq    $8, %rsp
    .cfi_def_cfa_offset 8
    ret
    .cfi_endproc
.LFE0:
    .size    main, .-main
    .ident    "GCC: (GNU) 6.4.1 20170727 (Red Hat 6.4.1-1)"
    .section    .note.GNU-stack,"",@progbits

可以看到,MyFunction.s(源文件为.c文件)中定义的是Function,而main.s(源文件为.cpp文件)中调用的是_Z8Functionii,函数名不一样,所以连接的时候找不到函数实现。到这里我们知道C和C++编译期间后得到的函数符号不同,所以C++代码和C代码不能互相调用。

  • 要想实现C、C++混合编程该怎么办呢?让编译后的函数符号一致;

  • 怎么一致呢?用extern "C"!

所以,extern “C”的作用就是告诉C++编译器,将指定的函数用C规则编译(注意,除了函数重载外,extern “C”不影响C++的其他特性),然后后面的事情就顺理成章了。

参考链接

extern C里面能有C++代码吗? - 知乎

Language linkage - cppreference.com

Standard C++

  • 134
    点赞
  • 355
    收藏
    觉得还不错? 一键收藏
  • 16
    评论
### 回答1: "extern C++" 是一个 C++ 的关键字,通常用于在 C++ 代码引用 C 代码的函数或变量。 在 C++ ,函数名由编译器自动重载,以便支持函数重载。这意味着在 C++ 存在多个函数名相同但参数类型和数量不同的函数。这与 C 不同,因为在 C ,所有函数都必须有唯一的名称。 当 C++ 代码需要调用 C 代码的函数时,需要使用 "extern C++" 关键字来告诉编译器该函数使用 C 的命名约定,而不是 C++ 的命名约定。 例如,在 C 代码定义了一个函数: ```c int add(int a, int b); ``` 在 C++ 代码调用该函数时,需要使用 "extern C++" 关键字: ```c++ extern "C" { int add(int a, int b); } ``` 这将告诉编译器该函数使用 C 的命名约定,因此可以在 C++ 代码正确地调用该函数。 ### 回答2: extern "C" 是用在C++的关键字,主要用于在C++代码调用C语言的函数或变量。 C语言和C++语言有一些不同之处,最主要的区别是它们的函数名和变量名的命名规则不同。在C语言,函数名和变量名是平级的,没有命名空间的概念,并且符号的重载、函数的重载等特性都不存在。而C++语言引入了命名空间的概念,允许同一个函数名在不同的命名空间重载定义,还支持符号的重载,函数的重载等特性。 当C++代码需要调用一个C语言的函数或变量时,由于C语言的命名规则和C++不同,C++编译器无法直接将C语言的函数名或变量名理解C++代码的函数或变量。为了解决这个问题,就需要使用 extern "C" 来告诉编译器这是一个C语言的函数或变量,让编译器按照C语言的命名规则去处理。 extern "C" 的作用是用来修饰一段C语言的代码,告诉编译器按照C语言的规则来处理这段代码。在C++,使用 extern "C" 修饰的代码可以在C++调用。 一般情况下,extern "C" 会和 C 语言的头文件一起使用,例如:extern "C" { #include "c_header.h" }。这样,c_header.h的函数和变量就可以在C++代码正常使用。 总之,extern "C" 是C++的关键字,用于在C++代码调用C语言的函数或变量,并告诉编译器按照C语言的规则处理这些代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值