【问题标题】:When don't I need a typedef?我什么时候不需要 typedef?
【发布时间】:2009-02-05 15:34:22
【问题描述】:

我遇到了一些代码阅读

typedef enum eEnum { c1, c2 } tagEnum;

typedef struct { int i; double d; } tagMyStruct;

我听说这些结构源自 C。在 C++ 中你可以轻松编写

enum eEnum { c1, c2 };
struct MyStruct { int i; double d; };

这是真的吗?什么时候需要第一个变体?

【问题讨论】:

    标签: c++ c typedef


    【解决方案1】:

    首先,这两种声明在 C 和 C++ 中都是合法的。但是,在 C 中,它们的语义略有不同。 (特别是,您稍后引用该结构的方式会有所不同)。

    要理解的关键概念是,在 C 中,结构存在于单独的命名空间中。 所有内置类型以及 typedef 都存在于“默认”命名空间中。也就是说,当我键入int 时,编译器只检查这个“默认”命名空间。如果我在您的示例中键入“tagMyStruct”,编译器也只检查这个命名空间。但根据您使用的声明类型,该结构可能不存在于该命名空间中。

    结构是不同的,存在于单独的命名空间中。因此,如果我做出以下声明:

    struct mystruct {};
    

    我可以简单地将其称为 mystruct。相反,我必须指定我想要存在于 struct 命名空间中的 mystruct:

    void foo(struct mystruct bar); // Declare a function which takes a mystruct as its parameter
    

    从长远来看,这会变得有点冗长和尴尬。相反,您可以将其 typedef 到默认命名空间中:

    typedef struct mystruct mystruct; // From now on, 'mystruct' in the normal namespace is an alias for 'mystruct' in the struct namespace
    

    现在,我的函数可以直接声明:

    void foo(mystruct bar);
    

    所以您的第一个示例只是将这两个步骤合并在一起:声明一个结构,并将一个别名放入常规命名空间。当然,由于我们无论如何都要对它进行类型定义,我们不需要“原始”名称,因此我们可以使结构匿名。所以在你的声明之后

    typedef struct { int i; double d; } tagMyStruct;
    

    我们有一个没有名称的结构,它在默认命名空间中已被类型定义为“tagMyStruct”。

    C 就是这样对待它的。这两种类型的声明都是有效的,但一种不会在“默认”命名空间中创建别名,因此每次引用该类型时都必须使用 struct 关键字。

    在 C++ 中,不存在单独的结构命名空间,因此它们的含义相同。 (但首选较短的版本)。

    编辑 明确一点,不,C 没有命名空间。不是通常意义上的。 C 只是将标识符放入两个预定义的命名空间之一。结构(和枚举,我记得)的名称放在一个中,所有其他标识符放在另一个中。从技术上讲,它们是命名空间,因为它们是单独的“容器”,其中放置名称以避免冲突,但它们肯定不是 C++/C# 意义上的命名空间。

    【讨论】:

    • 所以 C 确实 有命名空间! :) 谢谢,这澄清了很多事情。
    • xtofl:不,不是。不是 C++ 意义上的。结构和内置类型存在于不同的命名空间中,但除此之外,没有。你不能声明新的命名空间,或者任何你期望的东西。所以这有点特殊。将其视为“C 具有命名空间”可能是个坏主意;)
    • 要点是“命名空间”是一个完美的词,在 C++ 使用它来指代它自己的用户定义命名空间的特定概念之前。您也可以说 C 预处理器添加了另一个命名空间(用于宏),与 C 保留其名称的空间不同。
    • 我不会为此责怪 C++。但是,是的,命名空间肯定比 C++ 实现具有更基本的含义。归根结底,它只是区分相同名称的能力,通过将它们存储在单独的“空间”中,并且该概念以某种形式存在于大多数语言中。跨度>
    • 不要忘记联合标签。它们与 struct 标记共享相同的命名空间 - 您不能在同一范围内同时拥有 'union u { ... }' 和 'struct u { ... }'。
    【解决方案2】:

    在 C 中,如果你要写

    struct MyStruct { int i; double d; };
    

    当你想引用那个类型时,你必须指明你在谈论一个结构:

    struct MyStruct instanceOfMyStruct;
    struct MyStruct *ptrToMyStruct;
    

    使用 typedef 版本:

    typedef struct { int i; double d; } tagMyStruct;
    

    你只需要写:

    tagMyStruct instanceOfMyStruct;
    tagMyStruct *ptrToMyStruct;
    

    typedef 版本的另一大优势是您可以在 C 和 C++ 中以相同的方式引用结构,而在第二个版本中,它们在 C 中的引用方式与在 C++ 中不同。

    【讨论】:

    • “只需要写”版本是“tagMyStruct ...”iso“MyStruct”吗?或者这是正确的吗? (这是违反直觉的......)
    【解决方案3】:

    这只是简写。

    在第二种情况下,要声明你要这样做的结构:

    struct MyStruct a;
    

    在第一个变体中,您可以这样做:

    tagMyStruct a;
    

    【讨论】:

    • 这也是 C 语言的简写吗?还是只指 C++?
    【解决方案4】:

    第二个变体也存在于 C 中。

    只要你想命名你的类型,你就可以使用第一个变体,例如:

    tagEnum myFunc(tagMyStruct * myArg);
    

    【讨论】:

      【解决方案5】:

      第一个在 C++ 中可能不方便,因为您不能在头文件中前向声明它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-09-16
        • 1970-01-01
        • 2010-09-21
        • 2018-02-25
        • 1970-01-01
        • 1970-01-01
        • 2017-05-23
        相关资源
        最近更新 更多