在头文件中使用 extern 的优点

2023-12-01

这里有一个类似的问题标题,但在阅读答案时,它似乎没有解决该特定问题:C: 头文件中的“extern”有什么用?(它更像是“为什么使用头文件?”)。

在下面的用法中extern:

extern int a;
int b;

// structs have no external linkage 
typedef struct Item_ {int id;} Item;
extern Item Item_Extern;

void main(void) {

}

// later in the program or another file
int a=4;
int b=5;
Item Item_Extern = {1};

如果出现以下情况,编译器是否会生成任何不同的程序集:extern使用,或者这更多是类型的元数据标记,以便代码(或编译器)的用户将明确知道该定义将出现在不同的文件中(通常)或稍后出现在当前文件中,并且如果事实并非如此,这将是一个严重的错误。或者,确实extern‘做’其他事吗?


介绍

There are three forms of declaration of concern here:1

extern int x; // Declares x but does not define it.
int x;        // Tentative definition of x.
int x = 0;    // Defines x.

声明产生一个标识符(一个名称,例如x) known.

A definition creates an object (such as an int).2 A definition is also a declaration, since it makes the name known.

在同一翻译单元(正在编译的源文件及其所有包含的文件)中没有常规定义的暂定定义就像初始值设定项为零的定义一样。

通常使用它们的方式应该是:

  • For an object you will access by name in multiple files, write exactly one definition of it in one source file. (It can be a tentative definition3 if you would like it to be initialized with zero, or it can be a regular definition with an initializer you choose.)
  • 在关联的头文件中(例如foo.h对于源文件foo.c),声明名称,使用extern如上图所示。
  • 在使用该名称的每个文件中包含头文件,包括其关联的源文件。 (后者很重要;当foo.c包括foo.h,编译器将在同一个编译中看到声明和定义,如果存在导致两个声明不兼容的拼写错误,则会向您发出警告。)

事实上,你正常使用它们的方式应该是根本不使用它们。程序通常不需要对象的外部标识符,因此您应该在没有它们的情况下设计程序。上述规则适用于您何时使用它们。

暂定定义

在Unix和其他一些系统中,已经可以给出一个暂定的定义,int x;,在一个头文件中并将其包含在多个源文件中。由于暂定定义的作用类似于没有常规定义的定义,因此这会导致多个翻译单元中存在多个定义。 C 标准没有定义其行为。那么它在 Unix 中是如何工作的呢?

Until recently, when you compiled with GCC (as built by default), it created an object file that marked tentatively defined identifiers differently from regularly defined identifiers. The tentatively defined identifiers were marked as “common.” When the linker found multiple definitions of a “common” identifier, it coalesced them into a single definition. Remember, the C standard does not define the behavior. But Unix tools4 did. So you could put int x; in a header and include it in lots of places, and you would get one int x out of it when linking the entire program.

在版本 10 及更高版本中,GCC 默认情况下不执行此操作。在没有常规定义的情况下,临时定义更像是常规定义,并且与同一标识符的多个定义链接将导致错误,即使这些定义源自临时定义。 GCC 有一个选择旧行为的开关,-fcommon.

这是您应该了解的信息,以便您可以理解利用“常见”行为的旧源文件和标头。新的源代码中不需要它,您应该只编写非定义声明(使用extern) 在源文件的标头和常规定义中。

各种各样的

你不需要extern带有函数声明,因为没有主体的函数声明(包含函数代码的复合语句)自动成为声明,并且其行为与具有函数声明相同extern。函数没有暂定定义。

Footnote

1 This answer addresses only external declarations and external definitions for identifiers of objects, with external linkage. The full rules for C declarations are somewhat complicated, partly due to the history of C’s evolution.

2 This is for definitions of identifiers that refer to objects. For other kinds of identifiers, what is a definition may be different. For example, typedef int foo is said to define foo as an alias for the type int, but no object is created.

3 It may be preferable to also include an initializer, even if it is zero, as this will make it a regular definition and avoid a potential problem where the same name is used tentative definitions in two different source files for two different things, resulting in the linker not complaining even though this is an error.

4 I may be being sloppy with terminology here; somebody else could identify precisely where this behavior was specified and what tools it applied to.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在头文件中使用 extern 的优点 的相关文章

  • 这种对有效类型规则的使用是否严格遵守?

    C99和C11中的有效类型规则规定 没有声明类型的存储可以用任何类型写入 并且存储非字符类型的值将相应地设置存储的有效类型 抛开 INT MAX 可能小于 123456789 的事实不谈 以下代码对有效类型规则的使用是否严格符合 inclu
  • 仅针对某些异常类型中断

    我知道异常处理是一件非常重要的事情 我们在所有项目中都在这样做 主要原因是记录客户发生的错误 这工作正常 根本不是问题 但是 当我仍在使用 Visual Studio 编码和运行应用程序时 我根本不需要任何异常处理 我希望调试器正好停在应用
  • 如何修复此 YCrCb -> RBG 转换公式?

    我使用的公式来自这个问题 https stackoverflow com questions 8838481 kcvpixelformattype 420ypcbcr8biplanarfullrange frame to uiimage c
  • C# 中不区分大小写的替换不使用正则表达式?

    有没有一种方法可以在不使用 C 中的正则表达式的情况下对字符串进行不区分大小写的替换 像这样的东西 string x Hello x x Replace hello hello world 你可以尝试类似的东西 string str Hel
  • 我如何模拟 UserManager 和 RoleManager 进行单元测试

    我模拟了抽象类来测试类的具体方法 如下所示 var mock new Mock
  • 指向 VLA 的指针

    你可能知道 VLA 的优点和缺点 https stackoverflow com a 3082302 1606345在 C11 中它们是可选的 我认为使 VLA 成为可选的主要原因是 堆栈可能会爆炸 int arr n where n 10
  • VS C# 中的依赖地狱,找不到依赖项

    我创建了一个图表 C 库 我们称之为chartlibrary 它本身依赖于多个第三方 dll 文件 在另一个可执行项目中 我们称之为chartuser 我参考了chartlibrary项目 两个项目位于 Visual Studio 中的同一
  • 这个元组创建习惯有名字吗?

    On the 增加邮件列表 http lists boost org Archives boost 2014 06 214213 php LouisDionne 最近发布了以下创建类似元组的实体的巧妙技巧 include
  • C# SignalR 异常 - 连接在收到调用结果之前开始重新连接

    我正在开发 2 个应用程序 第一个是 C 控制台应用程序 另一个是 Asp net Web 应用程序 我正在使用 SignalR 连接两者 这是我的 C 控制台应用程序 客户端 public class RoboHub public sta
  • PowerShell 与 MongoDB C# 驱动程序方法不兼容?

    由 C 泛型引起的最新 MongoDB 驱动程序的问题 Cannot find an overload for GetCollection and the argument count 1 我可能可以使用其他没有泛型的 GetCollect
  • 在 boost 元组、zip_iterator 等上使用 std::get 和 std::tie

    我有哪些使用选择std get lt gt and std tie lt gt 与增强结构一起 例子 我想使用基于范围的 for 循环在多个容器上进行迭代 我可以实施zip函数 它使用boost zip iterator include
  • 来自用户定义文字的整数字符序列,以字符串作为参数

    目前 只有双精度数可以在用户定义的文字中生成字符模板 template
  • 如何使用 MongoDB 实现 ASP.NET Core 3.1 Identity?

    是一个 API 用于简化后端和逻辑代码来管理用户 密码 个人资料数据 角色 声明 令牌 电子邮件确认等 对于 Visual Studio 来说 支撑脚手架 https learn microsoft com en us aspnet cor
  • 智能感知不显示评论

    如果我在 Visual Studio 2010 中输入类似的内容数据集1 我得到所有可用方法和属性的列表 智能感知 这很好用 但是 如果我在此列表中选择一个方法或属性 我不会得到 if 的描述 例如 如果我有类似的东西 public cla
  • 在 C++ 中什么时候首选传递指针而不是引用传递?

    我可以想象一种情况 其中输入参数可以为 NULL 以便首选传递指针而不是传递引用 有人可以添加更多案例吗 在传递的对象实际上将被修改的情况下 有些人更喜欢传递指针 当对象通过引用传递时 它们使用 pass by const referenc
  • 曲线/路径骨架二值图像处理

    我正在尝试开发一个可以处理图像骨架的路径 曲线的代码 我想要一个来自两点之间骨架的点向量 该代码在添加一些点后结束 我没有找到解决方案 include opencv2 highgui highgui hpp include opencv2
  • SQL Server CE 不兼容的数据库版本

    我有一个 SQL Server CE 4 0 数据库 sdf文件 当我尝试从我的应用程序 WPF 对数据库进行查询时 出现以下错误 数据库版本不兼容 如果这是兼容文件 请运行修复 其他情况请参考文档 数据库版本 4000000 请求的版本
  • 如何编写完全可移植的 4 字节字符常量的编译时初始化

    遗留 代码大致如下所示 define MAKEID a b c d UInt32 a lt lt 24 UInt32 b lt lt 16 UInt32 c lt lt 8 UInt32 d define ID FORM MAKEID F
  • 使用 List.Contains 方法为 LINQ 构建表达式树

    Problem 我正在重构一些LINQ查询我们的 Web 应用程序中的多个报告 并且我尝试将一些重复的查询谓词移至它们自己的中IQueryable扩展方法 以便我们可以将它们重新用于这些报告以及将来的报告 正如您可能推断的那样 我已经重构了
  • 在地图上使用 find

    如何使用 find 和 aconst iterator如果你有一个地图定义为 typedef std pair

随机推荐

  • 如何将我自己的 jQuery 版本与浏览器化模块一起使用

    我应该预先澄清 我的问题是关于 Javascript 中的闭包和客户端模块模式 这不是关于如何使用 jQuery noConflict 我有一些 Javascript 人们可以将其添加到他们的网站中 我希望我自己的代码能够访问 变量 该变量
  • Java 中的 Arrays.fill 多维数组

    如何在不使用循环的情况下在 Java 中填充多维数组 我试过了 double arr new double 20 4 Arrays fill arr 0 这导致java lang ArrayStoreException java lang
  • Objective-C SSL 同步连接

    我对 Objective C 有点陌生 但遇到了一个我无法解决的问题 主要是因为我不确定我是否正确实现了解决方案 我正在尝试使用同步连接使用自签名证书连接到 https 站点 我正在得到 错误域 NSURLErrorDomain代码 120
  • NSFetchedResultsController ,其中包含由字符串的第一个字母创建的部分

    在 iPhone 上学习核心数据 关于核心数据用部分填充表视图的示例似乎很少 这核心数据手册示例使用部分 但它们是从模型中的完整字符串生成的 我想按照姓氏的第一个字母将核心数据表组织成多个部分 就像地址簿一样 我可以为每个人创建另一个属性
  • SWF 对象 - 我为什么要使用它

    我的所有网站都需要对搜索引擎友好 即搜索引擎可读 然而 我有点喜欢flash并且希望以友好的方式集成它 我可以选择 swfobject 它允许正确的页面名称并向用户和搜索引擎提供不同的页面 但是 我想知道为什么需要使用 swfobject
  • fmt.Scanf 在 Go 中无法正常工作

    我正在尝试一个应该测试 fmt Scanf 的片段 但它似乎没有按预期工作 package main import fmt time func main fmt Println What is your favorite color var
  • 类型错误:super() 至少需要 1 个参数 [Python 3] [重复]

    这个问题在这里已经有答案了 在下面的代码中 尽管我重新检查了超过 15 分钟 但仍然出现相同的错误 为了您的信息 我在 sublime text 上运行它并出现错误 类型错误 super 至少需要 1 个参数 给定 0 个 代码如下所示 c
  • Fruchterman Reingold 的吸引力如何与 Boost Graph Library 配合使用

    我正在 Boost Graph Library 中学习 Fruchterman Reingold 算法 通过阅读文档 我知道该算法是根据图形布局计算所有节点的位置 但我的问题是我无法理解Boost Graph Library中吸引力的计算步
  • 套接字断开通知方法

    只是寻找一个可能的解决方案来识别客户端何时断开连接 我找到了这个 public bool IsConnected Socket s try return s Poll 1 SelectMode SelectRead s Available
  • Pandas 按唯一计数分组作为新列

    我想添加一个新列col在我的 pandas 数据框中 计算公式为 select count distinct ITEM as col from base data where STOCK gt 0 group by DEPT CLAS DA
  • 如何使用 watir-webdriver 禁用 Firefox 中的下载窗口?

    我不想处理 Firefox 或 IE 中的下载窗口 我想自动下载excel文件 没有任何下载窗口 我尝试为 Firefox 设置几个配置参数 但没有成功 在我的测试中 我尝试下载 Excel 文件 profile Selenium WebD
  • wxpython。需要帮助解决令人困惑的错误

    该代码适用于另一台计算机上的其他人 但似乎不适用于我 我正在使用 python 2 7 7 它对另外两个人来说效果很好 但它似乎不喜欢我或我的计算机 因为每当我运行它时 它都会给我一条错误消息 你们有什么感想 Traceback most
  • 3G 条码阅读器

    我是 iPhone 应用程序的新手 但最近我看到一个帖子 要求为 3G iPhone 提供条形码读取器 人们 包括我 提到过zxing它适用于 3GS 或更高版本 如果您想申请 3G 那么最好从 QuickMark 或 Red Laser
  • PHP在post请求中读取xml

    所以 我执行了两个步骤 a 在其中一个 php 文件中创建一些随机 xml 文件 b 解析第二个文件中的相同 xml 文件 关键点是 a 中的 php 文件将向 php 文件 b 发出仅 xml 作为请求的 post 请求 文件 b 必须使
  • Perl 中最小的非零正浮点数是多少?

    我有一个 Perl 程序 它处理的概率有时可能非常小 由于舍入误差 有时其中一个概率为零 我想做以下检查 use constant TINY FLOAT gt 1e 200 my prob calculate prob if prob 0
  • sha1() 用于密码哈希

    我使用 sha1 来保证密码安全 我以这种方式将密码存储在register php中 secure password salt openssl random pseudo bytes 20 secured password sha1 pas
  • HTML5 Canvas putImageData,翻译它,更改图像

    我想使用 HTML5 画布绘制图像 翻译图像 然后更改图像 但保留我所做的转换 这可能吗 这是一些伪代码来说明我的问题 initially draw an image and translate it var context canvas
  • 如何在Python中打印嵌套列表的所有可能性?

    这是我的清单 pos det noun adj noun vb det vb noun adj Or pos det noun adj noun vb det vb noun adj 我正在尝试打印所有组合 det noun noun vb
  • 为什么要修复 E_NOTICE 错误?

    作为一名开发人员 我在打开 E NOTICE 的情况下工作 最近有人问我为什么应该修复 E NOTICE 错误 我能想到的唯一原因是纠正这些问题是最佳实践 还有其他人有任何理由证明花费额外的时间 成本来纠正这些问题是合理的吗 更具体地说 如
  • 在头文件中使用 extern 的优点

    这里有一个类似的问题标题 但在阅读答案时 它似乎没有解决该特定问题 C 头文件中的 extern 有什么用 它更像是 为什么使用头文件 在下面的用法中extern extern int a int b structs have no ext