【问题标题】:Are different translation units allowed to define structures with the same name?是否允许不同的翻译单元定义具有相同名称的结构?
【发布时间】:2016-03-29 08:28:39
【问题描述】:

假设我有a.cb.c,它们都定义了称为struct foo 的类型,具有不同的定义:

#include <stdio.h>

struct foo {
    int a;
};

int a_func(void) {
    struct foo f;
    f.a = 4;
    printf("%d\n", f.a);
    return f.a * 3;
}

 

#include <stdio.h>

struct foo { // same name, different members
    char *p1;
    char *p2;
};

void b_func(void) {
    struct foo f;
    f.p1 = "hello";
    f.p2 = "world";
    printf("%s %s\n", f.p1, f.p2);
}

在 C 语言中,这些文件是否可以作为符合标准的程序的一部分链接在一起?

(在 C++ 中,我相信这是单一定义规则所禁止的。)

【问题讨论】:

  • 当然...只要在任何给定上下文中只有一个定义可见。但是请注意 extern,不要链接到使用与访问它的定义不同的定义创建的对象...
  • 正如 dimitri 所说,技术上是的,但我会说这不是理想的编码风格。
  • 编码风格没有问题,与extern无关。
  • 这里提到“编码风格”的人从来没有做过玩具程序,也不了解编程的基础知识。当你的程序有成百上千个模块,由几十个程序员编写,并与许多库链接时,你当然会出现许多同名的不同类型定义。库中的每个树实现都可能有一个名为Node 的结构。这是正常和好的。外部链接的变量和函数是完全不同的事情,与这个问题无关。 [我在这里的最后评论。]
  • @JimBalter 没有人会“向你靠拢”,也没有人说链接器看到了不同的类型定义。关键是,当要从不同的源文件链接外部对象时,有必要确保不同的声明实际上引用相同类型的数据,而不仅仅是相同的类型名称。你显然知道这一点......正如你所说,“这是基本的”......所以我不知道你为什么这么激动。

标签: c struct one-definition-rule


【解决方案1】:

结构标签是无链接的标识符(C11 6.2.2/6)

6.7/3 中关于无链接标识符的多重定义规则:

如果标识符没有链接,则在相同范围和相同名称空间中的标识符声明(在声明符或类型说明符中)不得超过一个,除了:

  • 可以重新定义 typedef 名称以表示与当前相同的类型,前提是该类型不是可变修改的类型;
  • 标签可以按照 6.7.2.3 中的规定重新声明。

在你的程序中,foo 的两个声明在不同的作用域中,所以不满足“具有相同作用域”的条件,因此不违反这条规则。

【讨论】:

    【解决方案2】:

    考虑这个问题的方式是compilation units。一个.c 文件以及包含的.h 文件的嵌套层次结构组成一个compilation unit。预处理器展开所有.h 文件,并将整个compilation unit 呈现给编译器。

    compilation unit 是宏、类型名称、静态标识符、枚举等的封闭命名空间。这些名称在此命名空间内不能有重复项,并且这些名称在此命名空间外均不可见。这意味着不同的compilation unit 是一个单独的、封闭的命名空间——并且可以重用相同的标识符,只要在那个命名空间中没有重复。 p>

    因此,您可以为某些标识符使用相同的名称,只要它们位于不同的 compilation unit 命名空间中。

    请注意,非静态全局变量、函数等外部可见标识符需要在整个外部命名空间中是唯一的,该命名空间跨越所有链接在一起的compilation units,成为一个可执行文件。

    【讨论】:

    • 在你说“命名空间”的地方,标准 C 术语是“范围”。在标准 C 中,“命名空间”不是一个东西,“命名空间”意味着别的东西。您的“外部命名空间”将描述“具有外部链接的标识符”的集合
    • namespace 这里使用的是一个通用术语。在某些系统(语言)中,该术语被明确采用以暗示相似的语义。但是namespace 是计算中的常用术语。
    【解决方案3】:

    在 C 编程语言中,你如何称呼你的类型并不重要。符号是根据类型的结构进行类型化的,而不是根据类型名称。在不同的文件中为不同的结构类型使用相同的结构名称是完全合法的。但是,您不能使用不同的类型来声明相同的函数。

    【讨论】:

    • 这很混乱。 C 有名义类型,而不是结构类型。这里的问题与此无关,而是关于范围。由于符号定义在不同的范围内,所以它们是独立的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 1970-01-01
    • 2019-10-14
    相关资源
    最近更新 更多