extern "C"用法总结

本文详细介绍了在C++程序中使用C代码时如何利用extern C防止函数名称重整的问题,同时提供了实例代码说明如何正确地在C程序中引用C++函数。

经常看到如下代码:

#ifdef _cplusplus

extern "C" {

#endif

#include "XXX.h"

#ifdef _cplusplus

}

#endif

解释:

extern "C"的作用是,告诉C++编译器,下面的代码按照C的方式进行编译,说白了,不要对这些函数进行名字重整(function name mangling)。通常在C++程序中使用C函数或者模块时,需要用到这个功能。

原因:

C++为了支持函数重载,将编译后的函数名做了重整(mangled name),比如下面的函数

int add(int a, int b) ;

在C中编译完的名字就是add,而在C++中,编译完就变成了add_int_int(举例而已,实际因编译器而异),这样在函数名字后面加上参数的类型,就可以区分不同的重载函数了,比如还有另一个函数

float add(float a, float b) ;

在C++中,它会被编译成add_float_float,这就是C++区分重载函数的机制

可是问题也随之而来

C++进行名字重整,而C不进行重整。当C++程序引用C的函数时,它会按照重整后的名字去目标文件(.obj)中去寻找对应的函数,而目标文件中存放的却是C版本的函数,名字对不上,所以根本找不到!

怎么办呢?

这就是extern “C” 存在的一个原因了

它告诉C++,包含在extern “C”{ //…}块中的东西是C版本的,你编译的时候不要进行名字重整,否则你链接的时候就无法找到我!

于是上面的代码也就不难理解了,光说不练是扯淡,上代码

我们简单的定义一个C头文件和实现文件,只包含一个add函数

CClass.h 内容如下

#ifndef __CClass_H__

#define __CClass_H__

extern int add(int a, int b) ;

#endif // end __CClass_H__

CClass.c 内容如下

#include "CClass.h"

int add(int a, int b)

{

return a + b ;

}

下面我们用一个C++程序来引用这个C文件

main.cpp 内容如下

#define _cplusplus // 为了测试,强加一句

#ifdef _cplusplus

extern "C" {

#endif

#include "CClass.h"

#ifdef _cplusplus

}

#endif

#include <iostream>

using namespace std ;

int main(void)

{

int result = add(1, 2) ;

cout << result << endl ;

system("pause") ;

return 0 ;

}

如果没有#include <iostream>之前那些代码而只是仅仅包含

#include "CClass.h"一句

你就会得到下面的错误

error LNK2019:unresolved external symbol "int __cdecl add(int,int)" (?add@@YAHHH@Z) referenced in function _main

显然这是一个链接错误,因为找不到对应的函数定义

当然你也可以简写成下面的形式,直接在extern “C”块中包含你想调用的函数

extern "C"

{

int add(int a, int b) ;

};

#include <iostream>

using namespace std ;

int main(void)

{

int result = add(1, 2) ;

cout << result << endl ;

system("pause") ;

return 0 ;

}

这在C++程序中是没有问题的,但是如果是在C程序中,则会出现编译错误,因为C中不允许extern “C”出现

另一个需要extern “C”的场合是当C程序调用C++的东西时

按照如下步骤做即可

1. 在C++的.h文件中用extern “C”{}声明将被C程序使用的函数

2. 在C++的.cpp文件中实现上面的函数

3. 在.c文件中用extern声明要使用的C++函数

4. 使用即可

注意:切不可在.c文件中包含C++的.h文件,那样编译无法通过

上代码:

CPPClass.h中声明add函数

#ifndef __CPPClass_H__

#define __CPPClass_H__

extern "C"

{

int add(int a, int b) ;

};

#endif // end __CPPClass_H__

CPPClass.cpp实现add函数

#include "CPPClass.h"

int add(int a, int b)

{

return a + b ;

}

main.c 内容如下

#include <stdio.h>

//#include "CPPClass.h" // 不要包含头文件,否则编译不过

extern int add(int a, int b) ; // 只需显示声明要调用的函数即可

int main(void)

{

int result = add(1, 2) ; //使用函数

printf("%d", result) ;

return 0 ;

}


其他参考:http://songpengfei.iteye.com/blog/1100239


<think>好的,用户想了解C语言extern关键字的使用方法。我需要先回忆一下extern的基本概念和应用场景。extern主要用于声明变量或函数,表明它们是在其他文件中定义的,这样编译器在编译当前文件时就知道这些变量或函数的存在,而不会报错。 首先,我应该解释extern的作用,比如在多个源文件间共享全局变量或函数。需要分情况讨论,比如extern变量和extern函数的使用区别。对于变量,如果在另一个文件中已经定义了全局变量,那么在当前文件中用extern声明就可以使用它,而不会导致重复定义。对于函数,虽然函数默认是extern的,但在某些情况下显式声明可能有助于代码清晰。 接下来,应该给出一些具体的例子,比如在两个不同的.c文件中如何使用extern来共享变量。比如在file1.c中定义int global_var,然后在file2.c中用extern int global_var来声明,这样file2就可以访问这个变量了。同时,链接时的注意事项也要提一下,确保多个文件一起编译。 还要注意,如果在头文件中使用extern声明变量,那么包含该头文件的源文件都可以访问这个变量,但需要在某个源文件中实际定义它,否则链接时会出错。这点需要强调,避免用户出现未定义的错误。 另外,可能需要提到extern "C"在C++中的用法,但用户问的是C语言,所以这部分可能不需要详细展开,但可以稍微提一下,避免混淆。 还要考虑用户可能的常见错误,比如多次定义变量,或者忘记定义导致链接错误。比如,在头文件中如果没有使用extern而直接定义变量,那么多个包含该头文件的源文件会导致重复定义,这时候应该用extern在头文件中声明,并在一个源文件中定义。 最后,总结extern的关键点:声明而非定义,跨文件共享,避免重复定义,函数声明默认extern等。确保用户能够理解正确的使用场景和方法。在</think> C 语言中,`extern` 关键字用于**声明**一个变量或函数,表明其定义存在于其他文件(或同一文件的其他位置),从而实现在不同作用域或文件之间共享数据或函数。以下是其核心用法和注意事项: --- ### 一、核心作用 1. **跨文件共享全局变量** 当多个源文件需要访问同一个全局变量时,在**一个文件中定义**该变量,在其他文件中用 `extern` 声明即可使用,避免重复定义。 2. **提前声明函数或变量** 如果函数或变量的定义在文件后面(或另一个文件),可用 `extern` 提前声明,告知编译器“此符号已存在,稍后定义”。 --- ### 二、具体用法 #### 1. 声明全局变量 - **定义全局变量**(分配内存) 在某个源文件(如 `file1.c`)中定义: ```c int global_var = 10; // 实际定义(分配内存) ``` - **在其他文件中使用** 在另一个文件(如 `file2.c`)中声明: ```c extern int global_var; // 声明(不分配内存) void func() { printf("%d\n", global_var); // 访问 file1.c 中的 global_var } ``` #### 2. 声明函数 - 函数默认具有 `extern` 属性(可省略),但显式声明可提高可读性: ```c // 在 file1.c 中定义函数 void print_msg() { printf("Hello from file1.c\n"); } // 在 file2.c 中声明并调用 extern void print_msg(); // extern 可写可不写 void test() { print_msg(); } ``` #### 3. 在头文件中使用 - **推荐做法**:在头文件中用 `extern` 声明全局变量,在某个源文件中定义它。 ```c // common.h extern int shared_value; // 声明 // file1.c #include "common.h" int shared_value = 100; // 实际定义 // file2.c #include "common.h" void use_value() { shared_value += 10; // 使用其他文件中定义的变量 } ``` --- ### 三、注意事项 1. **避免重复定义** `extern` 是声明而非定义,同一变量只能在一个文件中定义(不带 `extern`),否则链接时报错。 2. **初始化问题** `extern` 声明时不能初始化变量(如 `extern int x = 5;` 是错误的)。 3. **局部变量无效** `extern` 不能用于函数内的局部变量,仅作用于全局范围。 4. **静态全局变量(static)** 若全局变量用 `static` 修饰,表示仅限本文件使用,无法通过 `extern` 跨文件访问。 --- ### 四、示例场景 **项目结构**: ``` main.c utils.c utils.h ``` - **utils.h**(声明): ```c extern int counter; // 声明全局变量 extern void log_data(); // 声明函数 ``` - **utils.c**(定义): ```c #include "utils.h" int counter = 0; // 实际定义变量 void log_data() { // 定义函数 counter++; printf("Counter: %d\n", counter); } ``` - **main.c**(使用): ```c #include "utils.h" int main() { log_data(); // 输出 Counter: 1 log_data(); // 输出 Counter: 2 return 0; } ``` --- ### 五、总结 - **核心目的**:跨文件共享数据/函数,避免重复定义。 - **关键规则**:`extern` 是声明,定义必须唯一且不带 `extern`。 - **函数默认 extern**:函数声明时 `extern` 可省略,但变量必须显式使用。 合理使用 `extern` 能提升模块化编程效率,但滥用可能导致代码耦合,建议配合头文件管理全局变量。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值