【问题标题】:Is there a technical reason for the "struct namespace" in C?C中的“结构命名空间”有技术原因吗?
【发布时间】:2015-01-28 12:51:54
【问题描述】:

在 C 中,大部分声明结构的代码都遵循这种模式:

/* struct forward-declaration */
typedef struct T T ;

/* struct definition */
typedef struct T
{
   /* etc. */
} T ;

这种情况非常普遍,与我交谈过的大多数开发人员甚至都不知道上面的代码同时做了两件事(结构声明,然后在正常命名空间中为结构名称起别名),只是出于习惯而编写它。

在 C++ 中,该问题已得到缓解,因此您可以省略类型定义部分。在 C# 和 Java 中,设计者甚至都懒得理会。所以这些语言无助于理解为什么 C 会这样做。

所以,经过Oliver Charlesworth的建议:

struct T 置于与其他普通标识符不同的命名空间中是否存在技术原因?

编辑

C89/C90标准中的相关部分是:

6.1.2.3 标识符的命名空间

在翻译单元的任何位置都可以看到多个特定标识符的声明。句法上下文消除了引用不同实体的用法的歧义。因此。不同类别的标识符有单独的命名空间,如下:

  • [...]

  • 结构、联合和枚举的标签(通过使用关键字structunionenum)。

  • [...]

  • 所有其他标识符。称为普通标识符(在普通声明符中声明或作为枚举常量声明)。

C11(n1570:6.2.3 标准草案)的文本大致相同。

【问题讨论】:

标签: c namespaces


【解决方案1】:

直到 typedef 被添加到复杂的解析中,对象声明总是以保留字开头:structintcharcharfloatdouble,可能还有 longunion(不确定是在typedef 之前还是之后添加的)。由于结构标签只能出现在关键字struct 之后,因此编译器没有理由关心结构标签是否与任何其他标识符共享名称。

typedef 名称与任何其他标识符的名称不同的需要是由于允许在对象声明或转换表达式中使用自定义类型而产生的语法歧义,而无需任何保留字或标点符号(在开头一个函数,x * y; 可以创建一个名为y 类型为x* 的对象,或者可以将x 乘以y 并丢弃结果,(x)(y) 可以将y 转换为@987654339 类型@ 或使用参数y 调用函数x)。

【讨论】:

    【解决方案2】:

    仅当您想在第二个声明中使用名称 T 引用 struct T 时才需要第一行。

    对于不包含此类引用的结构,只需要第二种形式。对于这种情况,为了简单起见,我建议删除 then 无意义的 struct 标签:

    typedef struct {
      /* interesting fields go here */
    } T;
    

    此外,typedef 不会“将结构名称带入正常的命名空间”,它会创建(像 typedef 总是这样做)一个 别名 (T) 用于不同的输入名称struct T。当然这里的名字拼写之间没有任何联系,这就是为什么我建议首先放弃标记struct,它只是添加了一个大多数时候没有意义的名字。

    【讨论】:

    • 感谢您的回答,但是...它没有回答我的问题,即:是否有技术原因将结构类型命名空间与正常(函数和变量)命名空间分开。 (参见 C89/C90 标准,6.1.2.3 标识符的名称空间)
    • struct tagname 形式的另一个优点是可以在头文件中定义此类结构的指针、函数参数和函数返回类型,而不必担心是否包含完整的结构类型定义。范围。如果标头的某些用户将使用 importWidget 函数,该函数需要 struct Widget* 类型的参数,但其他人不会,并且在该原型中将类型标识为 struct tagName*,则客户端代码不使用该类型不需要包含它的定义。
    猜你喜欢
    • 2011-09-26
    • 2023-04-10
    • 1970-01-01
    • 2019-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-07
    相关资源
    最近更新 更多