【问题标题】:using struct keyword in variable declaration in C++在 C++ 中的变量声明中使用 struct 关键字
【发布时间】:2011-10-11 16:55:20
【问题描述】:

我感觉这可能与 C 语法有关,但我的编程生涯是从 C++ 开始的,所以我不确定。

基本上我已经看到了:

struct tm t;
memset( &t, 0, sizeof(struct tm) );

我对这种语法有点困惑,因为通常我希望上面看起来像这样:

tm t;
memset( &t, 0, sizeof(tm) );

两者有什么区别,为什么用前者代替?

更新

我所指的结构tmwchar.h中,定义如下:

struct tm {
        int tm_sec;     /* seconds after the minute - [0,59] */
        int tm_min;     /* minutes after the hour - [0,59] */
        int tm_hour;    /* hours since midnight - [0,23] */
        int tm_mday;    /* day of the month - [1,31] */
        int tm_mon;     /* months since January - [0,11] */
        int tm_year;    /* years since 1900 */
        int tm_wday;    /* days since Sunday - [0,6] */
        int tm_yday;    /* days since January 1 - [0,365] */
        int tm_isdst;   /* daylight savings time flag */
        };

【问题讨论】:

  • struct tm 来自标准 C 库,应该在 time.h 而不是 wchar.h 中找到
  • 可能是,但它也在我平台上的 wchar.h 中(MSVC)。结构定义包含在ifndef 保护检查_TM_DEFINED 中,但这与我原来的问题无关。
  • @Praetorian 事后看来只是重复。我最初的困惑来自不同的角度,这仍然是有价值的,并且是查找可以说是相同信息的有效且有用的替代方法。

标签: c++ struct


【解决方案1】:

简单的答案是 struct 关键字的存在将标识符 tm 的查找限制为仅用户定义的类类型。它可能是为了与 C 兼容而留下的。

与其他人所说的相反,没有 auto-typedef 这样的东西,C 和 C++ 在管理用户定义类型的标识符方面也没有区别。唯一的区别在于查找。

您可以阅读更多here

【讨论】:

  • C 和 C++ 在如何管理用户定义类型的标识符方面确实存在两种不同。首先,在 C 中,structs、unions 和 enums 的名称位于单独的名称空间中,在查找这些关键字后面的名称时,使用该名称空间代替正常的名称空间。这样的名称永远不会与 C 中的其他名称发生冲突,并且除非它们遵循这些关键字之一,否则永远不会找到这样的名称。 C++ 有允许冲突并解决冲突的特殊规则,但前提是存在冲突。
  • 与 C++ 不同的是,在 C 中,即使在另一个 struct 中定义了一个 struct,它的名称也好像是在封装 struct 之外定义的。因此,在 C++ 中,struct A { struct B {}; }; 定义了两个结构:AA::B。在 C++ 中,它还定义了两个结构体:struct Astruct B
  • @JamesKanze:从概念上讲,C++ 仍然维护这两个命名空间,不同之处在于如果在通用命名空间中查找失败,则将查找用户定义的类型。与在 C 中一样,用户定义类型的名称不能与其他标识符(变量、函数)冲突——typedef 会导致标识符被添加到通用名称空间中,这可能会导致问题。同样,正如我之前所说,区别不在于查找。另一个区别(嵌套结构)是正确的,并且与 C 语言中标识符的缺失有关。
  • 这不是 C++ 标准描述它的方式。 §3.3.10/2 谈到在同一范围内声明其他内容时“隐藏”类名或枚举名,而 §3.3.1/4 谈到在相同范围内声明类名或枚举名其他名称。
  • §3.4/1 还说“名称查找规则统一适用于所有名称(包括 typedef-names (7.1.3)、namespace-names (7.3) 和 class-names (9.1))只要语法允许在特定规则讨论的上下文中使用此类名称。”据我了解,规则是另一个名称将隐藏类或枚举名称,除非在另一个名称不能合法出现的上下文中(实际上,仅在详细的类型说明符中)。
【解决方案2】:

在 C 中,结构标记名称不构成全局名称空间上的标识符

struct not_a_global_identifier { /* ... */ };

要引用该结构,您必须使用关键字struct(指定名称空间)

struct not_a_global_identifer object;

或在全局名称空间中创建一个新标识符,使用typedef

typedef struct not_a_global_identifer { /* ... */ } global_name_space_identifier;

C中有4个命名空间,见C99 Standard中的6.2.3:

  • 标签名称
  • 结构、联合和枚举的标签
  • 结构或联合的成员(不是一个单一的命名空间......与定义的结构或联合一样多)
  • 全局名称空间,用于所有其他标识符

这是一个合法的 C 程序 :-)

int main(void) {
  typedef struct foobar { int foobar; } foobar;
  foobar boo;
  boo.foobar = 42;
  if (boo.foobar) goto foobar;
foobar:
  return 0;
}

【讨论】:

  • 所以基本上考虑到这一点,在 C 中我可以声明一个名为 struct foo {}; 的全局结构,并且在它旁边还有一个同名的全局变量 int foo; 并且不会发生冲突?
  • 是的。您可以在不同的名称空间中拥有相同的标识符而不会出现问题。在上面的代码中,foobar 同时是一个类型(global 命名空间)、一个结构成员(member 命名空间)、一个结构标签(标签命名空间)和一个标签(标签命名空间)。
  • @RobertDailey:不仅在 C 中,您还可以在 C++ 中这样做,然后您将遇到必须添加 struct(或 class)来声明变量的问题:@ 987654333@ 之前在x的定义中去掉struct关键字会导致编译错误。
  • 非常感谢,现在很清楚了。我突然发现这是一种两层的想法......如果它不在当前的那个到struct的抽屉里找到foobar
【解决方案3】:

使用struct tm t;是为了与C兼容,其中声明一个名为“tm”的结构定义了一个名为“struct tm”的类型,但不是一个名为“tm”的类型(与C++相反,其中类型的两个名称都已声明)。

【讨论】:

    【解决方案4】:

    用户定义的类型有自己的标识符空间,即当编译器解析文件时,它将每个标识符存储在其对应的空间中。

    当您引用tm 时,C 编译器(作为 C++ 编译器)将在全局标识符空间中搜索此标识符。如果之前没有找到符号,C++ 编译器将在用户定义类型标识符空间中查找。

    基本上,如果您想拥有与 C++ 中相同的行为,请添加以下行:

    typedef struct tm tm;
    

    你可以像这样结合结构声明和类型定义:

    typedef struct tm { int field } tm;
    

    或者使用匿名结构:

    typedef struct { int field } tm;
    

    同样的行为适用于enumunion

    typedef enum { VALUE } myEnum;
    typedef union { int integer; char charArray[4]; } myUnion;
    

    【讨论】:

    • 自动 typedef 只是做我所做的,但自动。由于 C++ 更注重类型,因此类型是直接可用的。 C 更侧重于变量的含义,因此重要的是要知道 t 是一个 struct tm,而不仅仅是一个 tm。请注意,枚举和联合也会发生同样的事情
    • C++ 中也没有 auto typedef。 typedef 的作用是在全局标识符空间中声明一个新标识符以引用用户定义类型标识符空间中的类型。也就是说,typedef struct tm tm; 创建了一个新标识符tm 来引用struct tm。 typedef 的行为在 C 和 C++ 中完全相同。实际区别在于查找,其中 C++ 将自动在用户定义类型标识符空间中查找标识符如果之前未找到该标识符
    • @DavidRodríguez-dribeas 您能否在您最后的声明中添加更多细节:will automatically lookup identifiers in the user-defined-types identifier space if the identifier was not previously found。不确定“用户定义类型标识符空间”是什么,也不知道您所指的确切查找逻辑是什么。
    • @RobertDailey:你可以阅读更多here
    • @DavidRodríguez-dribeas 谢谢大卫。您应该发布包含所有这些信息的实际答案!
    【解决方案5】:

    在您的示例中, tm 可能是一个类型转换的结构。

    例如

    typedef struct tm_t
    {
      int x; 
    }tm;
    

    然后你就可以了

    tm t; 
    

    【讨论】:

      【解决方案6】:

      您可以看到下面链接的参考并从那里引用“在 C 中,您必须显式使用 struct 关键字来声明结构。在 C++ 中,一旦定义了类型,这就是不必要的。”有关更多信息和示例,请参阅链接。

      http://msdn.microsoft.com/en-us/library/64973255%28v=vs.80%29.aspx

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-12-26
        • 1970-01-01
        • 1970-01-01
        • 2014-10-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多