为什么在C语言中可以定义一个变量两次?

2023-12-14

我一直在测试全局变量、定义和声明,但我在这种情况下停了下来:

main.c:

#include "stdio.h"

void func(void);
int a;

int main(void) {
    a = 20;
    printf("in main: %d\n", a);
    func();
    
    return 0;
}

add.c:

#include <stdio.h>

void func(void);
int a;

void func() {
    printf("in add: %d\n", a);
}

所以在C中这一行

int a;

意味着声明和定义,但我们知道不允许多次定义一个变量。那么,如果我们有两个定义和两个声明,为什么这段代码会编译呢?a? 我正在 CLion 中工作,当我按“转到定义/声明”时a在 main 中,它将指针移动到a在 add.c 中,当我在 add.c 中执行相同操作时,它会移回 main.c,所以我无法理解这里发生了什么。


除了任何功能之外,int x; is a 暂定定义,一些编译器和链接器将它们视为一种“协作定义”,其中可以在多个文件中以这种方式声明标识符,并且将导致仅定义一个对象。

由于历史的原因,C 的外部声明(函数外部的声明)规则有点复杂——C 是随着不同的人开发和实验而成长的,而不是根据我们今天所拥有的知识进行设计的。

定义: int x = 3;是一个定义。它都声明了标识符x并为一个保留内存int,并且它初始化int to 3.

声明: extern int x;是声明但不是定义。它声明了标识符x但不为其保留内存。

extern int x; gives x外部链接也是如此int x = 3;如果它出现在函数之外。外部链接意味着,当它们出现在不同的源文件中时,标识符的两个实例将被链接以引用内存中的同一事物。

C 标准规定,具有外部链接的标识符“应有”至多一个定义 (C 2018 6.9 5)。 (如果程序中使用了标识符,则必须有定义。如果表达式中没有使用标识符,则不需要定义。)

暂定定义: int x;是一个混合体。在函数之外,它是一种特殊的声明,称为暂定定义。 C 标准规定,如果翻译单元(正在编译的源文件及其包含的所有文件)中有暂定定义,并且没有常规定义,则将创建常规定义。

现在,如果你违反了“最多应该有”一个定义的规则,会发生什么?事情是这样的:这不是程序必须遵守的规则。当 C 标准说“应该”时,意味着如果程序遵守此规则,则行为将如 C 标准所述。如果程序违反此规则,C 标准不会定义该行为 (C 2018 4 2)。相反,我们让编译器和链接器定义行为,如果它们的设计者选择这样做的话。

当程序违反最多一个定义的规则时,编译器和链接器中的一种常见行为(但不是唯一的可能性)是:

  • 如果链接时有多个正则定义,则报错。
  • 如果有多个定义来自暂定定义,但来自常规定义的定义不超过一个,请将它们合并为一个定义。

这是 GCC 版本 10 之前的 GCC 和相关工具中定义的默认行为,并在 C 2018 标准 J.5.11 中有关常见扩展的信息部分中明确提到。在当前版本的 GCC 中,任何类型的多个定义默认都会被视为错误。您可以使用命令行开关请求旧行为-fcommon.

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

为什么在C语言中可以定义一个变量两次? 的相关文章

随机推荐

  • windows:获取监视器的数量,包括禁用的监视器

    EnumDisplayMonitors列出当前激活的所有监视器 但是 它似乎不会返回禁用的 即未选中 将我的桌面扩展到此显示器 的那些 我如何获得包括残疾人在内的计数 好的 首先您必须创建一个设备上下文 http msdn microsof
  • Windows 任务计划程序的问题

    我在使用 Windows 任务管理器时遇到两个问题 一 我有一个 Python 脚本 可以在运行结束时通过 gmail 发送电子邮件通知 当我运行脚本本身时 这工作正常 但是当我通过 Windows 任务计划程序运行脚本时 脚本运行良好 但
  • Struts 2 jQuery 网格从 JSON 字符串加载数据

    我发现我们可以加载jqGird与 JSON 字符串 请参阅将 JSON 数据映射到 jqGrid 是否可以使用此功能sjg grid tag 我查看标签属性 只发现可以从 URL 加载数据 该 URL 将调用 Struts 操作 并且该操作
  • 在 Android 中以编程方式切换到开发者模式

    我想创建一个工具 允许在 Android 版本低于 4 2 的 Android 设备上切换到开发人员模式 我想创建一个 apk 来激活和停用开发者模式 这可能吗 如何 开发人员 模式是一种系统设置 因此只能从系统应用程序进行修改 即使用制造
  • 为什么当我转换为“long”时会调用“operator bool()”?

    我有以下课程 class MyClass public MyClass char what controlled what MyClass delete controlled operator char const return contr
  • 如何在渲染时为 React 组件设置动画?

    我正在尝试为包含从其他地方获取的数据的 React 组件设置动画 将其放置在ReactCSSTransitionGroup工作得很好 也就是说 直到我改变了组件的render 返回方法false直到数据被获取 到防止在没有数据的情况下渲染它
  • 如何从 C# 显示文件的“属性”对话框?

    如何打开文件的特性通过按钮进行对话框 private void button Click object sender EventArgs e string path C Users test Documents tes text how t
  • Java 9、10、11、12...等中的 javax.smartcardio

    从 Java 9 开始 javax smartcardio 库发生了什么 有替代方法或某种方式在 JAR 中获取它吗 在网上搜索了几个小时后 感谢上面的答案 据我了解 Java 9 及更高版本是模块化的 这是几年前计划的语言改进 此外 在新
  • 将两个导航控制器添加到一个选项卡栏项目

    我希望将 2 个导航控制器附加到一个选项卡栏项目 基本上 这个想法是在单个选项卡项上有 2 个视图 并且应该有一个导航栏来推动和弹出屏幕 与 iPad 中的设置应用程序相同 已编辑 看起来左侧有一个带有自己的导航控制器的视图 而右侧有另一个
  • 如何在 Swift 中增加 plus 设备上的字体和大小?

    我观察了一些流行的应用程序 当我们比较 iPhone Plus 设备和普通设备时 字体和图像是不同的 iPhone Plus 设备中稍大一些 我们如何在 iOS 应用程序中实现同样的目标 我已经使用过闪屏了 但字体仍然是相同的 在 plus
  • 为IE6中新打开的窗口设置OnLoad事件

    我需要为新弹出的窗口设置 onload 属性 以下代码适用于 Firefox a href www google com 但是 当我在 IE 中尝试此操作时 出现错误 printwindow document body null 或未定义
  • 从屏幕坐标查找世界坐标

    这个问题有很多答案 但我不确定它们都适用于 XTK 例如在 Three JS 中看到了多个答案 但显然 XTK 和 Three JS 没有相同的 API 使用射线和Matrix似乎与其他框架的许多其他解决方案非常相似 但我仍然没有掌握可能的
  • 算法 - 如何在 O(K) 中查找 Kt'h 元素并构建 O(n)

    我需要在 O k 中找到包含无序 n 元素的数组输入的 K 元素 满足以下要求 1 构建可以是O n 您可以使用给定的数组构建您想要的任何数据结构 2 找到O k 中的第k个元素 该算法在假设数组中没有重复元素的情况下工作 预处理 找到中间
  • 如何查看一个分支中的哪些提交不在另一分支中?

    我有两个分行devel and next 在开发中 我或多或少有大量的提交 一些提交是精心挑选的next 我还添加了一些提交到 next 并合并到devel 现在我想看看缺少什么next 这样我就可以在将更改提交之前详细测试它们next 我
  • 在android中创建一个定时服务

    我需要用java在android中创建一个日程服务 我尝试了一些代码 但在构建应用程序后它始终无法运行 我的逻辑很简单 我想创建一个服务来检查蓝牙文件夹路径中是否存在文件 如果该文件存在 那么该服务将运行另一个应用程序 我需要每 2 分钟运
  • StreamReader 不接受字符串?

    我正在尝试使用 StreamReader 读取文件 但使用时出现错误path 参数 1 无法从 string 转换为 System IO Stream 尽管从文档 那个你should能够使用字符串 我在这里缺少什么 public MyCla
  • 下一个导出脚本不适用于下一个/图像组件

    我有一个项目 我想构建并导出它 但出现错误 这是我的构建脚本package json file scripts build next build next export 这是我正在使用的组件next image import Image f
  • 如何检查Python字典中的内部字典中是否存在某个键?

    有一个Python字典 a b c x 1 y 2 z 3 我想知道是否a b c z 存在 但我还不知道是否a b c or a b 都存在 所以 如果我这样做 if z in a b c 我可能会得到一个 key c doesn t e
  • 为什么 C++ 模板类型匹配不检索引用限定符“&”?

    我有以下程序 include
  • 为什么在C语言中可以定义一个变量两次?

    我一直在测试全局变量 定义和声明 但我在这种情况下停了下来 main c include stdio h void func void int a int main void a 20 printf in main d n a func r