extern关键字用法详解

article/2025/9/24 12:37:24

extern关键字会提升变量或者函数的逼格,使得它们可以跨文件被访问。话虽然是这么说,使用这个关键字必须要注意一些东西。

首先,你得在cpp文件里面实现这些全局变量全局函数,这是最基本的,然后只需要在需要用到这些变量和函数的文件里声明一下,用extern修饰声明,这样弄完之后就可以随意使用这些全局变量和全局函数了。请不要为编译器担心,担心它们找不到这些东西,只要你实现了,不怕编译器找不到。

在别的文件里写一堆的extern声明显得特别不专业,也显得代码十分臃肿,有没有好的做法呢?有的。

我们一般把所有的全局变量和全局函数都放在一个*.cpp文件里面,然后用一个同名的*.h文件包含所有的函数和变量的声明。用法的示例如下:

/*Demo.h*/

#ifndef _DEMO_H_ //保证头文件只被包含一次
#define _DEMO_H_extern int a;
extern int b;
int add(int a, int b);#endif
/**
//下面的写法也可以
#pragma  once   //保证头文件只被包含一次
extern int a;
extern int b;
*/

/*Demo.cpp*/

#include "Demo.h" 
int a = 10;
int b = 20;int add(int l, int r)
{return l + r;
}

/*main.cpp*/

#include "Demo.h"
#include <iostream>
using namespace std;void main()
{cout << "a = " << a << ", b = " << b << endl;int c = add(1, 2);printf("c = 1 + 2 = %d \n", c);system("pause");
}

运行结果如下:

这样处理之后只需要到用到的地方加入#include"Demo.h"一句即可,很方便吧!这么干方便了这些变量和全局函数的管理

下面是关于extern关键字的一些说明:

(1)extern声明全局变量

在A.cpp中使用B.cpp中的变量,需要extern声明。定义的形式类似于:

extern  int  a;

这里需要注意定义和声明的区别,extern  int  a = 10;属于定义了。

/*Demo.h*/

#ifndef _DEMO_H_
#define _DEMO_H_extern int a = 10;//应该只保留声明
extern int b = 20;//应该只保留声明
int add(int a, int b);#endif
/**
//下面的写法也可以
#pragma  once
extern int a;
extern int b;
*/

/*Demo.cpp*/

#include "Demo.h"
int a = 10;
int b = 20;int add(int l, int r)
{return l + r;
}

/*main.cpp*/

#include "Demo.h"
#include <iostream>
using namespace std;void main()
{cout << "a = " << a << ", b = " << b << endl;int c = add(1, 2);printf("c = 1 + 2 = %d \n", c);system("pause");
}

这么干肯定是编译不通过的,因为存在重定义,#include"Demo.h"这一句是单纯的代码替换,在Demo.cpp和main.cpp里替换之后你自然发现全局变量被定义了两次,肯定会报错。一句话,声明可以拷贝n次,但是定义只能定义一次(声明不分配内存空间,定义会分配内存空间,同一个变量不应该被分配多个内存空间)

(2)extern声明外部函数

在A.cpp中使用B.cpp中的函数,需要extern声明。

extern关键字的作用是告诉编译器,在某个cpp文件中,存在这么一个函数/全局变量。

函数的声明类似于:

extern  int  sum(int, int);

函数的声明语句中,关键字extern可以省略,因为全局函数默认是extern类型的,因此也就出现了Demo.h中的状况。

虽然用extern声明了变量和函数之后,在别的文件里就随意使用了,但是你也千万别忘了书写变量和函数的实现,否则就会出现无法解析的外部符号,编译无法通过。

还有一件很有趣的事情,如果你将前面的Demo.cpp改为Demo.c的话,编译器会告诉你说找不到变量和函数是无法解析的外部符号,怎么办呢?

之所以会出现这样的原因,是因为c++编译器和c编译器差异性的问题,C++语言在编译的时候为了解决函数的多态问题,会将函数名和参数联合起来生成一个中间的函数名称,而C语言则不会,因此会造成链接时找不到对应函数的情况,我们是在main.cpp文件里包含了Demo.h也就是在main.cpp里面声明了这么一些变量和函数(代入即可),main.cpp里面的声明会被c++编译器成处理中间的名称,而Demo.c里面的实现会被c编译器处理,两者处理的差异性(详情可以看我后面提供的链接),导致问题多多。总之处理之后.c文件的实现和.cpp里面的声明不一致了,这也是导致找不到的原因,这个时候就必须用extren "C"了,告诉c++编译器,请保持我的名称,不要给我生成用于链接的中间函数名。

我们将Demo.h里面的东西改一下写法即可:

/*Demo.h*/

#ifndef _DEMO_H_
#define _DEMO_H_#ifdef  __cplusplus
extern "C" {
#endifextern int a;extern int b;int add(int a, int b);#ifdef  __cplusplus
}
#endif#endif

/*Demo.c*/

//#include "Demo.h"
#include <stdio.h>
int a = 10;
int b = 20;int add(int l, int r)
{
#ifndef __cplusplusprintf("这是一个c程序!\n");
#endif // !_cplusplus#ifdef __cplusplusprintf("这是一个c++程序!\n");
#endif // !_cplusplusreturn l + r;
}

/*main.cpp*/

#include "Demo.h"
#include <iostream>
using namespace std;void main()
{
#ifdef __cpluspluscout << "这是一个c++程序" << endl;
#endif#ifndef __cpluspluscout << "这是一个c程序" << endl;
#endifcout << "a = " << a << ", b = " << b << endl;int c = add(1, 2);printf("c = 1 + 2 = %d \n", c);system("pause");
}

运行结果如上图,特别要声明一下__cplusplus,前面是两个_,在.c文件没有定义__cplusplus而cpp文件定义了__cplusplus,一不小心将__cplusplus写成了_cplusplus会出现什么呢?就是我下面的情况了。

/*Demo.h*/

#ifndef _DEMO_H_
#define _DEMO_H_#ifndef  _cplusplus
extern "C" {
#endifextern int a;extern int b;int add(int a, int b);#ifndef  _cplusplus
}
#endif#endif

/*Demo.c*/

//#include "Demo.h"
#include <stdio.h>
int a = 10;
int b = 20;int add(int l, int r)
{
#ifndef _cplusplusprintf("这是一个c程序!\n");
#endif // !_cplusplus#ifdef _cplusplusprintf("这是一个c++程序!\n");
#endif // !_cplusplusreturn l + r;
}

/*main.cpp*/

#include "Demo.h"
#include <iostream>
using namespace std;void main()
{
#ifdef _cpluspluscout << "这是一个c++程序" << endl;
#endif#ifndef _cpluspluscout << "这是一个c程序" << endl;
#endifcout << "a = " << a << ", b = " << b << endl;int c = add(1, 2);printf("c = 1 + 2 = %d \n", c);system("pause");
}

说实话,结果我挺震惊的,在Demo.c文件中定义的函数跑出一个“这是一个c程序”,也没什么,在一个cpp文件中的函数跑出一个“这是一个c程序”,我就很震惊了,原因我也不清楚,不过基本就是上面的解决方案了,最后说一下不在Demo.c包含#include"Demo.h"的原因,因为在extern “C”并不是为C所支持,其实也不算吧!

因为网上说.c文件没有定义_cplusplus而cpp文件定义了_cplusplus,如果真是这样在Demo.c包含#include"Demo.h"也不会出现问题,可是不知道是我的编译器原因还是什么的,c文件和cpp文件都没定义_cplusplus,因此有可能Demo.c包含#include"Demo.h"出现问题,因为为了能在cpp文件中使用,Demo.h文件里我一般要写成#ifndef_cplusplus,此时若Demo.c包含#include"Demo.h",恰好c文件中也没有定义_cplusplus,那么extern “C”就暴露出来了,自然会错。


http://chatgpt.dhexx.cn/article/ZjfANi4x.shtml

相关文章

extern 声明用法

变量声明向编译器保证变量以给定的类型和名称存在&#xff0c;这样编译器在不需要知道变量完整细节的情况下也能继续进一步的编译。变量声明只在编译时有它的意义&#xff0c;在程序连接时编译器需要实际的变量声明。 当您使用多个文件且只在其中一个文件中定义变量时&#xf…

extern C语言的用法

extern用作从其他.c文件调用变量&#xff08;一般是全局变量&#xff09;和调用其他.c文件的函数&#xff08;当然不能调用其他.c文件的main函数哈哈哈哈哈哈&#xff09; 比如从test.c文件要从test1.c文件调用test1.c文件的int te全局变量和test1.c文件的Print()函数&#xff…

【C语言】extern 关键字

&#x1f6a9;write in front&#x1f6a9; &#x1f50e;大家好&#xff0c;我是謓泽&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f3c5;2021年度博客之星物联网与嵌入式开发TOP5&#xff5…

extern和static的用法

一&#xff1a;static static有两种使用&#xff1a;一种是修饰变量&#xff0c;另一种是修饰函数 1.修饰变量&#xff1a;作用是使得该变量在出了其作用范围后不会被销毁 第一种是修饰局部变量&#xff1a; 普通的局部变量是存储在栈区的&#xff0c;但是通过static修饰之后…

extern用法

1.extern变量&#xff0c;extern函数 extern 最简单的用法就是在一个文件中引用另一个文件中的变量或者函数。 首先我们要知道一个概念&#xff1a;声明可以有多次&#xff0c;定义只能有一次。 1.1extern变量 先来谈谈extern变量。 ① int a; ② int a 0; ③ extern int a…

C语言学习之extern关键字

1.了解extern 1.extern是C语言的一个关键字&#xff0c;可以用来修饰函数与变量 2.当extern修饰一个变量或函数时时&#xff0c;就是在声明这个变量(函数)&#xff0c;告诉编译器在外部文件中已经这个变量(函数)&#xff0c;要通过编译。 2.extern的用法 1.在一个文件中引用其…

extern关键字的一般用法

extern关键字会提升变量或者函数的逼格&#xff0c;使得它们可以跨文件被访问。话虽然是这么说&#xff0c;使用这个关键字必须要注意一些东西。 首先&#xff0c;你得在cpp文件里面实现这些全局变量和全局函数&#xff0c;这是最基本的&#xff0c;然后只需要在需要用到这些变…

C++中的extern

文章目录 extern的含义修饰全局变量修饰全局常量修饰局部变量修饰字符串C代码C代码 想必大家都知道&#xff0c;在C中&#xff0c;想要生成一个可执行文件&#xff08;exe&#xff09;或者动态链接库&#xff08;dll&#xff09;&#xff0c;需要经过编译和链接两个步骤&#x…

extern使用方法总结!

一、问题 Extern的问题在于不知道这个关键词出现的时候到底是声明还是定义&#xff1f; 二、详解 1、函数的声明extern关键词是可有可无的&#xff0c;因为函数本身不加修饰的话就是extern。但是引用的时候一样需要声明的。 2、全局变量在外部使用声明时&#xff0c;extern关键…

extern详解

extern——关键字 extern是C语言中的一个关键字&#xff0c;一般用在变量名前或函数名前&#xff0c;作用是用来说明“此变量/函数是在别处定义的&#xff0c;要在此处引用”&#xff0c;extern这个关键字大部分读者应该是在变量的存储类型这一类的内容中 遇到的&#xff0c;…

【014 关键字】一文彻底搞懂extern用法

一、定义和声明的区别 声明&#xff1a;用来告诉编译器变量的名称和类型&#xff0c;而不分配内存&#xff0c;不赋初值。 定义&#xff1a;为了给变量分配内存&#xff0c;可以为变量赋初值。 注&#xff1a;定义要为变量分配内存空间&#xff1b;而声明不需要为变量分配内…

HDU AWR电磁场与微波实验 操作记录

类型 滤波器版图设计功放设计IV曲线创建偏置电路&添加原理图背面注释添加谐波平衡端口添加双音激励端口 实验课需要使用这款软件 记录一下&#xff0c;提醒自己如何操作 工程文件如下 &#xff0c;0积分 滤波器. 版图. 功放. 交指滤波器. 滤波器 • Creating a schematic …

达梦AWR使用

DBMS_WORKLOAD_REPOSITORY 包 1、概述 AWR默认是关闭的需要受到开启&#xff0c;如 果 需 要 开 启 &#xff0c; 则 调 用 DBMS_WORKLOAD_REPOSITORY.AWR_SET_INTERVAL 过 程 设 置 快 照 的 间 隔 时 间 。 DBMS_WORKLOAD_REPOSITORY 包还负责 snapshot&#xff08;快照&…

AWR(性能报告)

本文章为网络笔记&#xff0c;看了warehouse老师的视频受益匪浅&#xff0c;更是感觉自己技术太过初级&#xff0c;特写了本笔记&#xff0c;方便以后反复学习&#xff01; 如有任何不妥&#xff0c;请发邮件至102448567qq.com删除文章&#xff01; 关于warehouse&#xff1a; …

AWR2243

TDA2xx-AWRx243 TI毫米波板&#xff08;代完善更新和作者的继续研究&#xff09; 1、安装mmwave studio和驱动&#xff08;链接&#xff1a; https://download.csdn.net/download/weixin_42501561/19775644 &#xff09; 2、设置网络端口IP地址&#xff08;如果不能更改路由器I…

awr报告

某客户反馈数据库慢&#xff0c;给到一份awr报告。分析如下 每个cpu可用处理时间3501.6s(59.86min)&#xff0c;系统负载为&#xff1a;511(59.86*16)50%,其中16为CPUs direct path read最高&#xff0c;可能有下面三种原因&#xff1a; parallel query大量disk排序table预读取…

awr清理

Oracle并没有真正进行删除AWR报告信息&#xff0c;查询metalink发现是Oracle的bug&#xff0c; Bug 8622802描述了这个问题&#xff0c; 修复版本&#xff1a; #禁用awr报告 EXEC DBMS_WORKLOAD_REPOSITORY.MODIFY_SNAPSHOT_SETTINGS(INTERVAL > 0); select * from WRM$_SN…

AWR

AWR自动工作量资料档案库: AWR用于收集关于该特定数据库的操作统计信息和其他统计信息&#xff0c;oracle以固定的时间间隔&#xff08;默认60分钟&#xff09;为其所有重要统计信息和负载信息执行一次快照&#xff0c;并将这些快照存储在AWR中。这些信息在AWR中保留给定的时间…

达梦 awr

AWR 全称为自动工作集负载信息库&#xff08;Automatic Workload Repository&#xff09; ,采集数据库的性能相关数据,用来分析数据库性能问题,方便调优工作。 达梦中 awr 功能默认是关闭的,另外 mpp 集群不支持 awr 开启 AWR 功能 检查 awr 开启状态 达梦提供了 SF_CHECK_AW…

ORACLE调优深入理解AWR报告

什么是AWR? 一堆历史性能数据&#xff0c;放在sysaux表空间上&#xff0c;AWR和sysaux都是10g出现的&#xff0c;是oracle调优的关键特性。 默认快照间隔1小时&#xff1b;10g保存7天&#xff1b;11g保存8天&#xff1b; 可以通过DBMS_WORKLOAD_REPOSITORY.MODIFY_SNAPSHOT_SE…