【问题标题】:Are synonymous `typedef`s in C interchangable?C中的同义词`typedefs可以互换吗?
【发布时间】:2016-02-05 23:20:02
【问题描述】:

声明qboolean SNDDMA_InitDirect (void); 出现在'WinQuake/snd_win.c' on line 69 中。但是,function's definition (appearing on line 183 of the same file 写为:

sndinitstat SNDDMA_InitDirect (void)
{
    /* Actual implementation is unimportant in this discussion. */
}

qbooleansndinitstat 都是枚举的typedefs:sndinitstat on line 33 of 'WinQuake/snd_win.c'

typedef enum {SIS_SUCCESS, SIS_FAILURE, SIS_NOTAVAIL} sndinitstat;

qboolean'WinQuake/common.h' (line 30)

typedef enum {false, true} qboolean;

这些是不同的枚举

我一直在通过 Visual Studio 的 LLVM 插件使用 Visual Studio 2015 的内置编译器 -- cl.exe -- 和 Clang v3.7.1 编译此源代码。 Clang 声明这种声明/定义的差异是一个错误。 Visual Studio 编译这个没问题。 谁是正确的?

现在引用C: A Reference Manual (Fourth Edition)

  • 5.5 枚举类型(第 127 页)

    枚举常量在定义类型时指定,类型为int

  • 5.10 类型定义名称(第 149 页)

    带有typedef 存储说明符的声明不会引入新类型;这些名称被认为是可以以其他方式指定的类型的同义词。

这两段在我听来好像 Clang 的错误虽然有帮助,但根据标准是不正确的。但我知道微软在正确编译 C 方面的声誉并不高。

【问题讨论】:

  • 他们是typedefs 的同一个枚举列表吗?或者换一种说法,你应该在问题中添加qbooleansndinitstat的定义。
  • C 标准解释的不一致在编译器之间并不少见。在我的编译器中,即使设置为最严格的设置,也不会将同一类型的不同别名识别为错误。在我看来,任何编译器最多应该将其标记为警告,而不是错误。
  • 我在链接中找到了typedef enum {SIS_SUCCESS, SIS_FAILURE, SIS_NOTAVAIL} sndinitstat;。你可以访问qboolean 的 typedef 吗?它在链接中被引用,但它的定义可能在其中一个头文件中。
  • @user3386109 - 如果两个别名的枚举相同,则需要 redeclaration 编译器错误。枚举必须完全不同。
  • 因为 Visual Studio 将匿名枚举视为类型 int。所以 typedef 等价于typedef int qbooleantypedef int sndinitstat。因此,Visual Studio 认为 qbooleansndinitstat 是同一类型。常识(和叮当声)说这是非常错误的。语言律师如何解释规范是有争议的,但有点毫无意义。如果对规范的正确解释表明 Visual Studio 是正确的,那么这只是意味着该规范大错特错。

标签: c visual-studio clang typedef


【解决方案1】:

它们引用不同的枚举:

typedef enum {false, true}  qboolean;
typedef enum {SIS_SUCCESS, SIS_FAILURE, SIS_NOTAVAIL} sndinitstat;

根据 6.2.5:16,

每个不同的枚举构成不同的枚举类型。

所以 Clang 肯定是正确的。

【讨论】:

    【解决方案2】:

    如果隐藏在 typedef 名称 qbooleansndinitstat 后面的枚举类型是兼容的,那么代码是可以的。如果它们不兼容,那么代码是错误的。 (见6.2.7 Compatible type and composite type)。

    如果两个函数声明都存在于同一个翻译单元中,则返回类型兼容性要求会变得更加严格,以至于类型必须相同

    在您的情况下,使用两种无标记枚举类型来定义这些 typedef 名称。枚举声明的差异足以使它们不兼容。这意味着有问题的代码确实包含错误,Clang 是正确的抱怨。 Visual Studio 错过了这个错误。

    请注意,尽管 Clang(以及 GCC)将其带到另一个极端 - 即使没有错误,它们也会报告错误。例如,这些声明

    enum { A1, A2, A3 } foo();
    enum { B1, B2, B3 } foo();
    

    在 Clang 和 GCC 中导致相同的错误,即使代码是有效的。在这个例子中,无标签枚举类型是兼容的,这足以证明声明之间foo的返回类型的变化是合理的。

    【讨论】:

    • 虽然另一个答案在技术上是正确的,但您的答案通过阅读材料提供了更深入的回应,因此我将其标记为已接受的答案。谢谢!
    • 我不相信这些类型是兼容的。该标准说(强调添加)“此外,如果它们的标签和成员满足以下要求,则两种结构、联合或枚举类型在单独的翻译单元中声明是兼容的:” . Clang 和 GCC 似乎在接受标准。
    • @rici:你是对的。 “......在单独的翻译单元中声明......”部分确实非常重要。我错过了。
    • @Alex Melbourne:我的回答并不完全准确。在您的情况下,当两个声明在同一个翻译单元中相遇时,就会发生冲突。在这种情况下,为了兼容,返回类型必须相同
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-02-13
    • 2013-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-29
    • 2017-12-08
    相关资源
    最近更新 更多