多次声明全局变量时,GCC 没有警告或错误[重复]

2024-07-04

假设有以下代码:

File a.c

#include <stdio.h>

int a;
int func();

int main(int argc, char **argv) {
    a = 7;
    int a2 = func();
    printf("a is %d, a2 is %d\n", a, a2);
    return 0;
}

File b.c

int a;

int func()
{
    a = 9;
    return a;
}

当编译时g++ a.c b.c -Wall -O0,正如预期的那样,它会产生链接错误。然而,当调用gcc a.c b.c -Wall -O0它不会产生任何警告或错误!

输出是a is 9, a2 is 9顺便一提。

gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)

为什么海湾合作委员会允许这样做?

我对这种行为感到惊讶。如果在声明时初始化变量,则 GCC 的链接也会失败。


当编译时g++ a.c b.c -Wall -O0正如预期的那样,它会产生链接错误。然而,当调用gcc a.c b.c -Wall -O0它不会产生警告,也不会产生错误!

在你的代码中,a has a 暂定定义(这变成了full定义在当前翻译单元的末尾),这在 C 中是有效的。

然而,还有另一个这样的暂定定义,它成为一个完整的定义b.c来自另一个翻译单元——两者都提供了外部定义a在你的程序中。换句话说,a.c and b.c它们本身就很好,但是当它们组合在一起编译时(无论是直接编译还是将它们编译成单独的模块,然后通过链接它们来生成可执行文件),它都是无效的。这是未定义的行为:

C11,6.9/5 https://port70.net/%7Ensz/c/c11/n1570.html#6.9p5:

外部定义是外部声明,也是函数的定义(内联定义除外)或对象。如果在表达式中使用通过外部链接声明的标识符(除了作为结果为整型常量的 sizeof 或 _Alignof 运算符的操作数的一部分),则在整个程序中的某处应该有一个该标识符的外部定义;否则,不得超过一个。161

然而,这通常作为 GCC 的扩展来支持。这就是为什么当你调用gcc,它可以很好地编译为 C 代码。严格来说(标准而言),这是 C 中的无效代码。

当你调用g++将其编译为 C++ 代码会失败,因为 C++ 没有暂定定义。它在 C++ 中无效。因此,g++错误输出。看一种定义规则 https://en.cppreference.com/w/cpp/language/definition in C++.

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

多次声明全局变量时,GCC 没有警告或错误[重复] 的相关文章

  • 如何扩展 C# 内置类型,例如 String?

    我需要Trim a String 但我想删除字符串本身内所有重复的空格 而不仅仅是在其末尾或开头 我可以用这样的方法来做到这一点 public static string ConvertWhitespacesToSingleSpaces s
  • 如何在 Blazor Web 程序集中检查客户端连接状态

    我有一个 Blazor webasemmbly 应用程序 它使用 asp net core 作为后端 使用 Blazor wasm 作为前端 我有一个类可以检查 HTTP 问题 例如 notfound BadReqest 和 public
  • 函数 try 块什么时候有用?

    我想知道程序员何时使用函数 try 块 什么时候有用 void f int i try if i lt 0 throw less than zero std cout lt lt greater than zero lt lt std en
  • TortoiseGit / Winforms:合并时解析 Resource.resx

    我对 TortoiseGit 还很陌生 想知道如果 resx 文件发生冲突 如何在合并过程中解决它 例如 我可以从菜单中选择 使用他们的 尝试进行拉动和推动 但这是正确的方法吗 我可以以某种方式使用他们的并通过我的项目更改重建它吗 差异 以
  • VSTO 功能区库,看起来像 Word 2010 中的样式选择器

    我正在用 C 编写功能区 COM 加载项 并尝试在新选项卡上创建可用模板文件库 是否可以将图库设置为像 Word ie 中主页选项卡上的样式选择器图库一样打开 显示图库中的所有文件名 MS 不允许其他人使用带内画廊在 Outlook 200
  • 如何在C语言中删除linux上的root权限?

    我想以非 root 用户身份分叉 执行和编程 同时父级保留 root 权限 伪代码 pid fork if pid 0 if RunAsUser ConvertStringToUserId John false stop if RunAsU
  • 查找表到底是如何工作的以及如何实现它们? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我最近编写了一个程序 该程序处理大量 if else 语句以返回特定值 有人建议改用查找表 我的问题是 它们是如何工作的以及您如何实施
  • 嵌入式Python,导入数学错误

    首先我使用的是 Mac OSX 10 12 6 我想在我的 C 应用程序中嵌入 python 环境 我把 github python 项目放在https github com python cpython https github com
  • C++:你会选择 boost::date_time 还是 icu::date/time 库?

    我的应用程序需要自定义时间和日期设置功能 我检查了 ICU 和 boost date time 库 从完整性的角度来看 两者似乎都满足我的要求 我想知道两者之间是否有任何偏好 依据是什么 哪一个会在表现上得分 如果没有有关您的特定用例和环境
  • XAML 页面中的 Bindable 值存在问题

    我有一个保龄球回顾示例代码 其中输入了 3 场比赛并总结在系列列中 我遇到的问题是系列列没有按照我的预期进行更新 显然 我做错了什么 但看不到我做错了什么 以下是支持该应用程序的代码
  • Google 的“编码折线算法”的 C# 实现

    有谁有 Google 的简洁而强大的实现吗 编码折线算法 http code google com apis maps documentation utilities polylinealgorithm html in C 我本质上想要实现
  • 如何知道机器的堆栈在内存中是向上还是向下增长? (JAVA)

    我有一个 C 程序来检查机器堆栈在内存中是向上还是向下增长 事情是这样的 include
  • C# 在字符串中创建下标

    目前我正在尝试修复我的应用程序中的一些格式 我正在尝试下标string并将其附加到正常的string 与在 MS Word 中执行的操作相同 我已经尝试过这个 正如假设的那样here https en wikipedia org wiki
  • 如何连接 COM 事件调度程序?

    VBIDE API 揭示了令人惊奇的神秘之处 dispVBComponentsEvents接口 除其他外 其中看起来像我可以用它来捕获 VBE 中各种有趣的事件 因此 我在一个类中实现了该接口 该类旨在捕获事件并引发 正常 net 事件以供
  • 迁移到新 csproj 格式的 WPF 应用程序上未定义 RunCommand 属性

    我正在尝试将旧 csproj 格式构建的 WPF 应用程序迁移到为 VS2017 定义的新 csproj 格式 我已经能够编译该应用程序 但是当我尝试在 VS2017 下的调试器中启动它时 我收到以下错误消息 无法运行您的项目 未定义 Ru
  • 无堆栈协程与堆栈协程有何不同?

    背景 我问这个问题是因为我目前有一个具有许多 数百到数千 线程的应用程序 这些线程中的大多数在很大一部分时间内处于空闲状态 等待将工作项放入队列中 当工作项可用时 它会通过调用一些任意复杂的现有代码来处理 在某些操作系统配置上 应用程序会遇
  • LINQ to SQL 未映射的属性

    是否可以在设计器中添加自定义属性并且不将其绑定到列 我摆弄了一些设置 决定用该属性创建一个部分类 有没有办法在 ORM 设计器中显示这个字段 LINQ to SQL 设计器正在维护映射 未映射的属性需要放入单独的分部类中
  • 在 ASP.NET MVC 2.0 中编辑实体框架中的对象并将其保存到数据库中

    所以我知道 EF 实体会跟踪它们自己的更改 并在调用 savechanges 时将它们保存到数据库中 但是这种情况怎么样 我有一个旨在编辑博客文章的页面 它有两种操作方法 HttpGet public ViewResult EditBlog
  • 如何使信号客户端避免表单身份验证?

    我的 MVC 网站在 web config 中有表单授权 现在所有的页面都需要通过授权才能被查看 但是现在我有一个控制台程序 C 控制台程序 这个程序需要发送一些消息到 SignalR 集线器 但是我的 signalR Hub 在我的 MV
  • 如何等待进程及其所有子进程退出?

    是否有一个等待方法 当目标进程及其所有子进程退出时会返回 看来 Process WaitForExit 只会等待目标进程 net 中有一个错误会给出您所追求的行为 WaitForExit 如果您异步读取输出 将等待所有子进程 p Start

随机推荐