c++中extern关键字

本文详细解析了C/C++中extern关键字的用途,包括如何声明在其他文件定义的变量和函数,链接指定的应用,以及extern与C/C++规则的关系。并提供了实际代码示例,帮助理解extern在不同场景下的应用。

extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。此外extern也可用来进行链接指定

  • 声明函数或全局变量的作用范围的关键字,其声明的函数和变量可以在本模块或者其他模块中使用,记住它是一个声明不是定义!

  • 链接指定。当它与"C"一起连用时,如: extern "C" void fun(int a, int b);则告诉编译器在编译fun这个函数名时按着C的规则去翻译相应的函数名而不是C++的,C++的规则在翻译这个函数名时会把fun这个名字变得面目全非,可能是fun@aBc_int_int#%$也可能是别的,因为C++支持函数的重载。

其他tips

与include相比,extern引用另一个文件的范围小,include可以引用另一个文件的全部内容。

extern 函数声明
  如果函数的声明中带有关键字extern,仅仅是暗示这个函数可能在别的源文件里定义,没有其它作用。即下述两个函数声明没有明显的区别:
extern int f(); 和int f();
  当然,这样的用处还是有的,就是在程序中取代include “*.h”来声明函数。关于这样做的原因和利弊可见下面的这个例子:“用extern修饰的全局变量”

(1) 在test1.h中有下列声明:

#ifndef TEST1H
#define TEST1H
    
extern char g_str[]; // 声明全局变量g_str
void fun1();

#endif

  (2) 在test1.cpp中

#include "test1.h"
       
char g_str[] = "123456"; // 定义全局变量g_str

void fun1() {
     cout << g_str << endl; 
}


    (3) 以上是test1模块, 它的编译和链接都可以通过,如果我们还有test2模块也想使用g_str,只需要在原文件中引用就可以了

#include "test1.h"

void fun2()   
{ 
    cout << g_str << endl;   
}

        以上test1和test2可以同时编译连接通过,如果你感兴趣的话可以用ultraEdit打开test1.obj,你可以在里面找到"123456"这个字符串,但是你却不能在test2.obj里面找到,这是因为g_str是整个工程的全局变量,在内存中只存在一份,test2.obj这个编译单元不需要再有一份了,不然会在连接时报告重复定义这个错误!
(4) 有些人喜欢把全局变量的声明和定义放在一起,这样可以防止忘记了定义,如把上面test1.h改为

extern char g_str[] = "123456"; // 这个时候相当于没有extern

      然后把test1.cpp中的g_str的定义去掉,这个时候再编译连接test1和test2两个模块时,会报连接错误,这是因为你把全局变量g_str的定义放在了头文件之后,test1.cpp这个模块包含了test1.h所以定义了一次g_str,而test2.cpp也包含了test1.h所以再一次定义了g_str,这个时候连接器在连接test1和test2时发现两个g_str。如果你非要把g_str的定义放在test1.h中的话,那么就把test2的代码中#include "test1.h"去掉 换成:

extern char g_str[];
void fun2(){  
    cout << g_str << endl;   
}

        这个时候编译器就知道g_str是引自于外部的一个编译模块了,不会在本模块中再重复定义一个出来,这样做非常糟糕,因为你由于无法在test2.cpp中使用#include "test1.h",那么test1.h中声明的其他函数你也无法使用了,除非也用都用extern修饰,这样的话你光声明的函数就要一大串,而且头文件的作用就是要给外部提供接口使用的,所以 请记住, 只在头文件中做声明,真理总是这么简单

<think>首先,用户的问题是:“我想了解C++extern关键字的作用和使用方法 请问C++ extern关键字作用及使用示例”。我需要基于提供的引用内容来回答,因为系统指令说“参考站内引用”,并列出了一些引用。 关键引用内容: - 引用[1]:extern 关键字可以应用于全局变量、函数或模板声明,指定符号具有 external 链接。作用是告诉编译器,符号在别处定义。常见使用场景:在a.cpp中使用b.cpp中定义的函数或全局变量。 - 引用[2]:externC++ 引入的关键字,用于全局变量、函数或模板声明,表示符号具有外部链接属性。C++ 全局变量默认作用范围限于当前文件,但支持分离式编译,extern 允许文件间共享数据。 - 引用[3]:详细比较了成员变量和 extern 声明的变量: - 作用域:成员变量在类范围内;extern 变量从声明点开始到文件结束或另一个声明。 - 存储位置:成员变量在对象实例中;extern 变量存储位置由定义决定。 - 使用方式:成员变量通过对象访问;extern 变量直接使用变量名访问。 - 还提到使用 extern 的好处。 - 引用[4]:在 C 库头文件中使用 extern "C" 的示例,用于 C++ 代码中调用 C 函数。 系统指令: - 所有行内数学表达式用 $...$,但这里没有数学内容,所以可能不需要。 - 独立公式用 $$...$$,但同样没有数学内容。 - LaTeX 语法正确:确保代码块正确。 - 使用中文回答。 - 生成相关问题:在回答结束时添加相关问题。 - 回答中引用的段落末尾自然地添加引用标识,如 [^1]。 - 回答结构清晰,逐步解决问题,保证真实可靠。 用户问题核心:extern 关键字的作用和使用方法。 结构回答: 1. **作用**:解释 extern 的作用。 - 基于引用,extern 用于声明外部链接的符号,告诉编译器该符号在别处定义,允许文件间共享数据。 - 好处:支持分离式编译,避免重复定义。 2. **使用方法**:提供使用示例。 - 场景1:在多个文件间共享全局变量。 - 场景2:在多个文件间共享函数。 - 场景3:使用 extern "C" 来调用 C 函数从 C++ 代码。 - 提供代码示例,使用代码块。 3. **示例**: - 例如,从引用[1]:在 a.cpp 中使用 b.cpp 中定义的变量或函数。 - 从引用[4]:extern "C" 的用法。 4. **添加引用标识**:在解释中自然地添加,如“extern 关键字的作用是告诉编译器,符号在别处定义 [^1]”。 5. **生成相关问题**:在结束时添加相关问题部分。 完整回答结构: - 引言:简要介绍 extern。 - 作用:详细解释。 - 使用方法:分点解释常见场景。 - 示例:代码示例。 - 总结。 - §§相关问题§§:列出2-3个相关问题。 确保中文回答。 代码示例:使用代码块,如: ```cpp // 示例代码 ``` 相关问题:基于主题,如: 1. extern 和 static 关键字的区别是什么? 2. 如何在 C++ 中使用 extern 来避免链接错误? 3. extern "C" 的具体应用场景有哪些? 现在,构建回答。</think>### C++extern 关键字的作用及使用方法 在 C++ 编程中,`extern` 关键字是一个重要的工具,用于处理符号(如变量、函数或模板)的链接属性。它允许程序在多个文件间共享数据或函数,支持分离式编译。下面我将逐步解释其作用、使用方法,并提供实际代码示例,确保内容真实可靠,基于权威引用。 #### 1. **extern 关键字的作用** `extern` 的主要作用是告诉编译器:某个符号(变量、函数或模板)在别处定义,而不是在当前文件中。这解决了 C++ 中全局变量和函数默认作用域限于当前文件的问题,使得不同文件可以共享数据或函数。关键作用包括: - **指定外部链接(external linkage)**:符号可以在多个文件间共享,编译器不会在当前文件中分配存储空间,而是链接到其他文件中的定义 [^1]。 - **支持分离式编译**:允许将大型程序分割为多个独立编译的文件,提高开发效率 [^2]。 - **避免重复定义错误**:在头文件中使用 `extern` 声明全局变量,可以防止多个源文件包含该头文件时导致的重定义错误 [^3]。 使用 `extern` 的好处包括: - 提高代码模块化和可维护性。 - 减少内存浪费,因为符号只定义一次。 - 便于跨文件调用函数或访问全局变量。 #### 2. **extern 关键字的使用方法** `extern` 的使用场景主要分为三类:全局变量、函数和 `extern "C"`(用于 C/C++ 互操作)。以下是常见方法及注意事项: - **场景 1: 在多个文件间共享全局变量** - **方法**:在一个文件中定义变量,在其他文件中用 `extern` 声明该变量。 - **为什么**:C++ 全局变量默认只在本文件有效,`extern` 扩展其作用域。 - **示例**: - 文件 `b.cpp` 中定义全局变量: ```cpp // b.cpp int globalVar = 42; // 实际定义 ``` - 文件 `a.cpp` 中使用 `extern` 声明该变量: ```cpp // a.cpp #include <iostream> extern int globalVar; // 声明,告诉编译器变量在别处定义 [^1] int main() { std::cout << "Global variable: " << globalVar << std::endl; // 输出 42 return 0; } ``` - **注意**:`extern` 声明不分配内存,只提供引用。定义必须出现在一个文件中(如 `b.cpp`),否则会导致链接错误。 - **场景 2: 在多个文件间共享函数** - **方法**:在头文件中用 `extern` 声明函数,在源文件中定义函数。 - **为什么**:允许函数被多个文件调用,避免重复定义。 - **示例**: - 头文件 `utils.h`: ```cpp // utils.h #ifndef UTILS_H #define UTILS_H extern void printMessage(); // 声明函数,extern 可省略(函数默认 extern) #endif ``` - 源文件 `utils.cpp`: ```cpp // utils.cpp #include "utils.h" #include <iostream> void printMessage() { // 实际定义 std::cout << "Hello from extern function!" << std::endl; } ``` - 另一个文件 `main.cpp`: ```cpp // main.cpp #include "utils.h" int main() { printMessage(); // 调用共享函数 return 0; } ``` - **注意**:对于函数,`extern` 通常可省略,因为函数默认具有外部链接。但显式使用可提高代码可读性 [^2]。 - **场景 3: 使用 `extern "C"` 调用 C 函数** - **方法**:在 C++ 代码中用 `extern "C"` 包裹 C 函数声明,避免名称修饰(name mangling)问题。 - **为什么**:C++ 编译器会对函数名进行修饰以支持重载,但 C 语言不支持。`extern "C"` 确保 C++ 能正确调用 C 库函数。 - **示例**(基于引用 [^4]): - C 库头文件 `clib.h`: ```cpp // clib.h #ifdef __cplusplus extern "C" { // 告诉 C++ 编译器:以下代码是 C 风格 #endif void cFunction(); // C 函数声明 #ifdef __cplusplus } #endif ``` - C++ 文件 `main.cpp`: ```cpp // main.cpp #include "clib.h" int main() { cFunction(); // 正确调用 C 函数 return 0; } ``` - **注意**:`extern "C"` 只用于声明,不用于定义。定义应在 C 源文件中。 #### 3. **注意事项和常见错误** - **作用域**:`extern` 声明的变量作用域从声明点开始,直到文件结束或另一个声明出现。成员变量则限定在类范围内 [^3]。 - **存储位置**:`extern` 变量存储位置由定义文件决定,而成员变量存储在对象实例中 [^3]。 - **错误避免**: - 确保符号只定义一次(例如,全局变量在单个文件中定义)。 - 避免在头文件中定义变量(用 `extern` 声明即可)。 - 链接时需确保所有文件一起编译(如使用 `g++ a.cpp b.cpp -o program`)。 #### 总结 `extern` 关键字C++ 中用于管理符号的链接属性,支持文件间数据共享和分离式编译。通过声明外部定义的变量或函数,它提高了代码的灵活性和可重用性。合理使用 `extern` 可以避免常见链接错误,尤其在大型项目中。如果您有具体代码上下文,我可以提供更针对性的建议。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值