C++ extern

externC用于解决C++和C语言混合编程时的链接问题,因为C++的函数重载会导致编译后的符号不同于C语言。externC告诉编译器按照C语言的方式处理函数,使得C++可以正确链接到C语言的函数。在头文件中使用externC块来声明C语言的函数,确保C++编译器不会添加函数参数类型的额外信息到符号名。
  • extern ˈekstɜ n外面的;外来的;对外的

当extern与"C"在一起修饰变量或函数时

  • C++ 与 C 编译区别
    在C++中常在头文件见到extern "C"修饰函数,那有什么作用呢? 是用于C++链接在C语言模块中定义的函数。

C++虽然兼容C,但C++文件中函数编译后生成的符号与C语言生成的不同。因为C++支持函数重载,C++函数编译后生成的符号带有函数参数类型的信息,而C则没有。

例如 int add(int a, int b) 函数经过C++编译器生成.o文件后,add会变成形如 add_int_int 之类的, 而C的话则会是形如 _add , 就是说:相同的函数,在C和C++中,编译后生成的符号不同。

这就导致一个问题:如果C++中使用C语言实现的函数,在编译链接的时候,会出错,提示找不到对应的符号。此时extern "C"就起作用了:告诉链接器去寻找_add这类的C语言符号,而不是经过C++修饰的符号。

  1. 被 extern “C” 修饰的变量和函数是按照 C 语言方式编译和连接的
  2. extern “C” 的作用是让 C++ 编译器将 extern “C” 声明的代码当作 C 语言代码处理,可以避免 C++ 因符号修饰导致代码不能和C语言库中的符号进行链接的问题。
#ifdef __cplusplus
extern "C" {
#endif

void *memset(void *, int, size_t);

#ifdef __cplusplus
}
#endif

在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern "C"声明,在.c文件中包含了extern "C"时会出现编译语法错误。所以使用extern "C"全部都放在于cpp程序相关文件或其头文件中。不过与C++调用C接口不同,C++确实是能够调用编译好的C函数,而这里C调用C++,不过是把C++代码当成C代码编译后调用而已。也就是说,C并不能直接调用C++库函数。

  • C++调用C函数:
//xx.h
extern int add(...)

//xx.c
int add(){
    
}

//xx.cpp
extern "C" {
    #include "xx.h"
}
  • C调用C++函数
//xx.h
extern "C"{
    int add();
}
//xx.cpp
int add(){
    
}
//xx.c
extern int add();

作用域扩展

  • 当 extern 不与"C"在一起修饰变量或函数时,如在头文件中:extern int g_Int;它的作用就是声明函数或全局变量的作用范围的关键字,其声明的函数和变量可以在本模块或其他模块中使用,记住它是一个 声明不是定义 也就是说编译单元B要是引用编译单元A中定义的全局变量或函数时,它只要包含A的头文件即可,在编译阶段,模块B虽然找不到该函数或变量,但它不会报错,它会在链接时从模块A生成的目标代码中找到此函数。

  • 注意:在使用extern时候要严格对应声明时的格式,比如在一个源文件里定义了一个数组:char a[6];,在另外一个文件里用下列语句进行了声明:extern char *a;这样是不可以的。但这同时也就造成另一个问题:如果函数原型被单方面修改的话,调用方在不知情情况下进行调用,在编译阶段不会报错,但是在运行时会由于参数类型不匹配而出错,所以现在大多只在头文件中进行声明并使用#include头文件的方式来引入函数而非extern。

  • extern的常用用法:在源文件中声明了一个全局的变量,这个全局的变量如果要被引用,就放在头文件中并用extern来声明。

  • 作用域扩展用法:

//"externTest.h"
#pragma once
#include <iostream>

int _g_o = 100;

void _g_fun() {
    std::cout << "Hello, World!" << std::endl;
    _g_o = 999;
}



// main.cpp
#include <iostream>
//不引入头文件会编译报错。没有引入情况下, extern int _g_o = 1;  这样是可以的 取值为1
//引入头文件情况下,不需要给_g_o 赋值,能共享 externTest 文件中定义的值
#include "externTest.h"

extern int _g_o;
extern void _g_fun();

int main() {
        std::cout << "_g_o: "<< _g_o << std::endl;//输出100
    _g_fun(); //能正常调用外部文件的方法
    std::cout << "_g_o: "<< _g_o << std::endl;//输出999
    return 0;
}

C++中,`extern`关键字主要用于声明变量或函数的外部链接(external linkage),即告诉编译器该符号(变量或函数)是在其他翻译单元(通常是另一个源文件)中定义的,当前的代码只是对其进行声明。`extern`的关键作用包括跨文件共享变量或函数、支持C与C++混合编程等。 ### 1. 跨文件共享变量或函数 当一个变量或函数在一个源文件中定义,而在另一个源文件中使用时,必须使用`extern`进行声明,以确保编译器知道该符号的定义在别处。例如,在一个文件中定义全局变量: ```cpp // file1.cpp int globalVar = 100; ``` 在另一个文件中使用该变量: ```cpp // file2.cpp extern int globalVar; #include <iostream> int main() { std::cout << globalVar << std::endl; // 输出 100 } ``` 这种方式使得多个源文件可以共享同一个全局变量或函数[^1]。 ### 2. C与C++混合编程 由于C++编译器会对函数名进行名称修饰(name mangling),而C语言不会,因此在C++代码中调用C语言编写的函数时,需要使用`extern "C"`来防止名称修饰,从而保证正确的链接。例如: ```cpp // c_code.c #include <stdio.h> void cFunction() { printf("Calling C function\n"); } ``` 在C++中调用: ```cpp // cpp_code.cpp extern "C" void cFunction(); int main() { cFunction(); // 正确调用 C 函数 } ``` `extern "C"`也可以用于声明多个函数或变量,通常用于包含C语言头文件时[^5]。 ### 3. 声明全局变量的外部链接 在头文件中使用`extern`声明全局变量,可以确保多个源文件在包含该头文件时不会导致重复定义错误。例如: ```cpp // globals.h #ifndef GLOBALS_H #define GLOBALS_H extern int sharedVar; #endif ``` 在某个源文件中定义该变量: ```cpp // source1.cpp #include "globals.h" int sharedVar = 42; ``` 其他源文件通过包含头文件即可访问该变量: ```cpp // source2.cpp #include "globals.h" #include <iostream> void printVar() { std::cout << sharedVar << std::endl; } ``` 这种方式保证了变量的唯一定义和多文件访问的可行性[^4]。 ### 4. 声明函数的外部链接 尽管函数的默认链接方式是外部链接,使用`extern`修饰函数声明是可选的,但在某些项目中,为了统一风格或明确意图,开发者可能会显式地使用`extern`来声明外部函数: ```cpp // header.h extern void externalFunction(); ``` 在源文件中定义: ```cpp // implementation.cpp #include <iostream> void externalFunction() { std::cout << "Function defined in another file" << std::endl; } ``` 这种做法虽然不是必须的,但有助于代码可读性和模块化设计[^4]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值