C中的extern关键字

C中的extern关键字应用于C变量(数据对象)和C函数。基本上,extern关键字扩展了C变量和C函数的可见性。这可能就是它诶命名为extern的原因。

虽然大多数人可能理解变量或函数的“声明(declaration)” 和 “定义(definition)” 之间的区别,但为了完整性,先澄清协议爱

  • 变量或函数的声明只是简单地声明变量或函数存在于程序中的某个位置,但没有为他们分配内存。变量或函数的声明起着重要作用——它“告诉”程序它的类型。在函数的声明中,它还“告诉”程序参数、数据类型、这些参数的顺序以及函数的返回类型。这就是声明的全部内容。
  • 说到定义,当我们定义一个变量或函数时,除了要做声明所做的一切之外,它还为该变量或函数分配内存。
  • extern是external的简称
  • 当某个特定文件需要访问另一个文件中的变量时,会使用extern变量。

C 中extern语法

在C中定义外部变量的语法只是在变量声明之前使用extern关键字。

extern data_type variable_name;

C中extern变量的例子

#include <stdio.h> extern int a;	 // int var; -> declaration and definition // extern int var; -> declaration 
int main() 
{ printf("%d", a); return 0; 
}

C中extern变量的属性

  • 当我们写 extern some_data_type some_variable_name; 时,没有分配内存。只声明了变量的属性。
  • 文件中允许有多个外部变量声明。但自动变量的情况并非如此。
  • extern变量对编译器说:“在我的范围之外,你可以找到我声明的变量的定义”
  • 编译器相信外部变量所说的一切都是真的,不会产生错误。当链接器发现不存在这样的变量的定义时,它会抛出错误。
  • 当一个外部变量被初始化时,就会为其分配内存,并将其视为已定义。

变量或函数可以声明任意次,但只能定义一次。(记住一个基本原则,即同一个变量或函数不能有两个位置。)

现在回到extern关键字。

首先,考虑函数中extern的使用。事实证明,当一个函数被声明或定义时,extern关键字是隐式假定的。当我们写

int foo(int arg1, char arg2);

编译器将其视为

extern int foo(int arg1, char arg2);

由于 extern 关键字将函数的可见性扩展到整个程序,因此可以在整个程序的任何文件中的任何位置使用(调用)函数,前提是这些文件包含函数的声明。(有了函数的声明,编译器就知道函数的定义存在于其他地方,然后继续编译文件)。这都是关于extern和函数的。

现在考虑变量中extern的使用。首先,如果在不定义变量的情况下声明变量?你可以这样做:

extern int var;

这里,声明了一个名为 var 的整数类型的变量(它还没被定义,所以目前为止还没有为 var 分配内存)。我们可以随心所欲地多次进行这样的声明。现在,如何定义 var?你可以这样做:

int var = 10;

在这一行中,声明定义了一个名为 var 的整型变量(请记住,定义声明的超集)。因为这是一个定义,因此还为 var 分配了内存。现在惊喜来了,当我们声明/定义一个函数时,我们看到 extern 关键字是隐式存在的。但变量的情况并非如此。如果是这样的话,就永远不会为它们分配内存。因此,当我们想要在不定义变量的情况下声明变量时,需要显式地包含 extern 关键字。此外,由于 extern 关键字将可见性扩展到这个程序,通过将 extern 关键字与变量一起使用,可以在程序中的任何地方使用该变量,只要包含其声明,变量的定义是在其他地方。

用一个例子来尝试理解 extern .

例1

int var; 
int main(void) 
{ var = 10; return 0; 
} 

程序编译成功。var是全局定义(并隐式声明)的。

例2

extern int var; 
int main(void) 
{ return 0; 
} 

程序编译成功。这里 var 仅仅声明了。注意 var 从未使用过,因此不会出现任何问题。

例3

extern int var; 
int main(void) 
{ var = 10; return 0; 
} 

程序在编译中抛出一个错误(在链接阶段),因为 var 声明了,但是没有在任何地方定义。本质上,var 没有分配任何内存。该程序试图将一个根本不存在的变量的值更改为10。

例4

// As we are importing the file and henceforth the 
// defination 
#include "somefile.h" // Declaring the same variable 
extern int var; // int var; // It will throw compiler error as compiler will get // confused where the variable is defined int main(void) 
{ var = 10; return 0; 
} // Now it will compile and run successfully

输出

10

注意: 这里出现了另一种情况,如果我们在上面的代码片段中不用extern声明呢?

考虑假设 somefile.h 文件中包含了 var 的定义,该程序将编译成功。当我们在一个文件中声明变量并在另一个文件中定义时,使用 ‘extern’ 关键字修饰变量。但在这里,当我们在声明该变量的文件中导入相同的文件时,将产生编译错误。

这是因为我们仍然必须在声明该变量的文件中使用 extern 关键字,以便告诉编译器该变量是在其他地方定义的,不会分配新的空间,否则它将创建另一个内存块,‘extern’ 关键字就没用了。

例5

extern int var = 0; 
int main(void) 
{ var = 10; return 0; 
} 

你认为这个程序会正常运行吗?好吧,这是来自C标准的另一个惊喜。如果一个变量只是被声明了,且在声明时也被初始化了,那么会为这个变量分配内存——换言之,这个变量认为是已经定义的。因此,按照C标准,这个程序成功编译并执行。

这是对 C 中 extern 关键字的初步研究。

简而言之,我们可以说:

  1. 可以执行声明任意次,但只能定义一次。
  2. extern 关键字用于扩展变量/函数的可见性。
  3. 由于默认情况下函数在整个程序中是可见的,因此在函数声明或定义中不需要使用 extern。它的使用是隐含的。
  4. 当 extern 与变量一起使用时,它只是声明,而不是定义。
  5. 例外情况,当一个变量在声明时被初始化,它被视为变量的定义。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/580972.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

月薪高达6W,多家大厂急招鸿蒙开发工程师,现在转还来得及吗?

近期&#xff0c;“安卓版本与鸿蒙不再兼容”的词条登上微博热搜&#xff0c;华为鸿蒙加速按下向“纯血鸿蒙”蜕变的启动键&#xff0c;欲与 iOS、安卓在市场三分天下。 一批嗅觉灵敏的互联网大厂&#xff0c;已经完成或开始启动开发鸿蒙原生 APP&#xff0c;也于近期发布了和…

十、Shell 变量类型

Shell 支持不同类型的变量&#xff0c;其中一些主要的类型如下&#xff1a; 一、整数变量 整型变量用于存储整数据数据。可以使用整数赋值给变量&#xff0c;或者通过命令的输出结果获取整数值。整型变量可以用于数学计算、循环控制等等。 #!/bin/bash num110 num25 su…

Java之ThreadLocal 详解

ThreadLocal 详解 原文地址&#xff1a;https://juejin.cn/post/6844904151567040519open in new window。 什么是ThreadLocal&#xff1f; ThreadLocal提供线程局部变量。这些变量与正常的变量不同&#xff0c;因为每一个线程在访问ThreadLocal实例的时候&#xff08;通过其…

视频流媒体直播云服务管理平台EasyNVS长时间运行出现崩溃情况是什么原因?该如何解决?

EasyNVS云管理平台具备汇聚与管理EasyGBS、EasyNVR等平台的能力&#xff0c;可以将接入的视频资源实现统一的视频能力输出&#xff0c;支持远程可视化运维等管理功能&#xff0c;还能解决设备现场没有固定公网IP却需要在公网直播的需求。 有用户反馈&#xff0c;在长时间不间断…

CGAL的D维范围树和线段树

范围树和线段树是两种数据结构&#xff0c;用于高效地处理和查询数据。 范围树&#xff08;Range Tree&#xff09;是一种二叉树&#xff0c;它通过递归地将每个节点分割成两个子节点来存储一个点集。每个节点表示一个范围&#xff0c;并且存储该范围内所有点的最小和最大值。范…

Mybatis 动态 SQL - script,bind,多数据库支持

script 在使用注解的映射器类中使用动态SQL时&#xff0c;可以使用<script>元素。例如&#xff1a; Update({"<script>","update Author"," <set>"," <if testusername ! null>username#{username},</if&g…

静物摄影在UE5里运用几点记要

被摄体&#xff0c;相机与光源的关系&#xff0c;要增强立体感&#xff0c;摄像机与光源的位置关系要错开&#xff1b;b的立体感要更强 漫反射与点光源&#xff0c;UE5太阳光属于漫反射&#xff0c;整体比较柔和&#xff0c;但是阴影处比较黑&#xff1b;摄影棚会用反光板来增亮…

如何让别人在你的私域疯狂消费?

要让别人在你的私域疯狂消费&#xff0c;首先&#xff0c;你得先打造自己的私域流量池。而打造私域流量池就需要明确你的目标客户群体&#xff0c;理解并满足他们的需求&#xff0c;有意识地向他们提供有价值的内容。 同时&#xff0c;通过创造力&#xff0c;精细化运营以及产品…

【模型】模型量化技术:动态范围、全整数和Float16量化

目录 一 动态范围量化 二 全整数量化 三 float16量化 通常&#xff0c;表示神经网络的数据类型是32位浮点数&#xff08;float32&#xff09;&#xff0c;这种数据类型可以提供高精度的计算&#xff0c;但是在计算资源和存储空间有限的设备上运行神经网络时&#xff0c;会带…

SpringBoot 异步编程浅谈

1. 需求背景 当我们需要提高系统的并发性能时&#xff0c;我们可以将耗时的操作异步执行&#xff0c;从而避免线程阻塞&#xff0c;提高系统的并发性能。例如&#xff0c;在处理大量的并发请求时&#xff0c;如果每个请求都是同步阻塞的方式处 理&#xff0c;系统的响应时间会…

Git使用教程 gittutorial

该教程对该文章的翻译&#xff1a;https://git-scm.com/docs/gittutorial 本文介绍怎用使用 Git 导入新的工程、修改文件及如何其他人同步开发。 首先&#xff0c; 可以使用以下指令获取文档帮助 git help log笔者注&#xff1a;不建议看这个文档&#xff0c;标准的语法介绍…

FreeRTOS的学习

1.创建函数和删除 动态创建为FreeRTOS分配的堆栈&#xff08;方便&#xff09;&#xff0c;而静态创建为人为分配空间。动态应用多任务中必须有while&#xff08;1&#xff09;否则只会执行一次任务中的延时要用 vTaskDelay(500); 延时期间执行其它任务 任务中的延时使…

postman进阶使用

前言 对于postman的基础其实很容易上手实现&#xff0c;也有很多教程。 对于小编我来说&#xff0c;也基本可以实现开发任务。 但是今年我们的高级测试&#xff0c;搞了一下postman&#xff0c;省去很多工作&#xff0c;让我感觉很有必要学一下 这篇文章是在 高级测试工程师ht…

01-Spring Security框架的认证和授权测试

Spring Security 介绍 认证功能与业务无关几乎是每个项目都要具备的功能,市面上有很多认证框架如Apache Shiro、CAS、Spring Security等 Spring Security是Spring家族的一份子且和Spring Cloud集成的很好&#xff0c;所以本项目采用Spring Security作为认证服务的技术框架 …

h5网页调用支付宝支付

1&#xff0c;调用依赖 支付宝开放平台官方api说的比较清楚&#xff0c;地址为下&#xff0c;还有联调 https://opendocs.alipay.com/open/29ae8cb6_alipay.trade.wap.pay?pathHash0a6313c7&refapi&scene21 pom文件调用 <dependency><groupId>com.alipay…

vue3(六)-基础入门之自定义组件与插槽、ref通信

一、全局组件 html: <div id"app"><mytemplace></mytemplace> </div>javascript: <script>const { createApp } Vueconst app createApp({})app.component(mytemplace, {template: <div><button>返回</button>…

canvas随机绘制100个五角星

canvas实例应用100 专栏提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。 canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重要的帮助。 文章目录 示例…

element-plus修改主题颜色

一、自定义scss文件 在src\css\styles\element目录下新建index.scss 代码如下 forward "element-plus/theme-chalk/src/common/var.scss" with ($colors: ("primary": ("base": #d61b1a,"color": #fff,),) );use "element-plus…

Java - 工厂设计模式

Java - 工厂设计模式 一. 简介二. 例子2.1 定义抽象类2.2 定义子类2.3 创建工厂2.4 测试 三. JDK中使用工厂模式的案例 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 工厂设计模式…

Day73力扣打卡

打卡记录 统计移除递增子数组的数目 II&#xff08;双指针&#xff09; 链接 class Solution:def incremovableSubarrayCount(self, a: List[int]) -> int:n len(a)i 0while i < n - 1 and a[i] < a[i 1]:i 1if i n - 1: # 每个非空子数组都可以移除return n …