【问题标题】:Nested structures嵌套结构
【发布时间】:2009-11-29 14:31:46
【问题描述】:

以下代码在 C++ 编译器上编译。

#include <cstdio>
int main()
{
    struct xx
    {
        int x;
        struct yy
        {
            char s;
            struct xx *p;
        };
        struct yy *q;
    };
}

在使用 C 编译器进行编译时,行为会有什么不同吗?
即会不会有任何编译器错误?

【问题讨论】:

  • 我没有 C 编译器。但是我在一个 C 文本中看到了这个例子,说这会导致编译器错误。

标签: c struct


【解决方案1】:

您帖子中的代码显然不完整,只是声明,因此很难说任何结论。

明显的区别在于,在 C++ 中,内部结构类型将是外部结构类型的成员,而在 C 语言中,两种结构类型将是相同(封闭)范围的成员。 (顺便说一句,您是否打算在 main 本地声明它们?)。

换句话说,在 C++ 中,后面的代码必须将结构引用为 xxxx::yy,而在 C 中它们将只是 xxyy。这意味着进一步的代码对于 C 和 C++ 看起来会有所不同,如果它会在 C++ 中编译,它就不会在 C 中编译,反之亦然。

补充: C 语言禁止在其他结构中声明结构类型而不声明该类型的成员。因此,您的 struct yy 声明在 C 语言中是非法的,并且会产生编译器诊断消息。如果您希望您的代码在 C 和 C++ 中都合法,则必须将 struct yy 声明与一些数据成员声明结合起来。在您的情况下,这可能是指针q

struct xx {
        int x;
        struct yy {
                char s;
                struct xx *p;
        } *q;
};

以上内容在 C 和 C++ 中都是合法的(考虑到我之前解释的差异),但您的原始声明在 C 中是不合法的。

【讨论】:

  • 对 c++ 的良好观察。但是你确定 struct yy 声明是非法的吗?除了警告之外,它可以与 gcc 一起正常编译,并且还会产生预期的行为。
  • 是的,我确定。 C 语言语法明确指出struct 的“内部”必须完全由声明符 组成。没有成员声明的struct 声明不是声明符。 GCC 接受它作为扩展。 GCC 有很多扩展。 GCC 不适合“尝试”以检查代码的合法性。 Comeau Online 在此方面做得更好。
  • 感谢您的澄清。根据你的说法,我改变了答案。不幸的是,我只得到一张赞成票。
  • 是否可以从结构 xx 外部访问结构 yy。我认为它只在 struct xx 范围内。如果您尝试在 main 但在 struct xx 之外声明 struct yy 对象,则必须在外部重新定义 struct yy,不是吗?我从阅读中了解到 C 中有 4 个命名空间,其中一个是 struct 的成员。但我想我把它和范围混在一起了......
  • @Rich:不,如果您在谈论 C。“嵌套”struct yy 声明的工作方式与 main 中的非嵌套 struct yy 声明相同。 IE。即使在struct xx 中声明了struct yy,您仍然可以在main 中声明struct yy obj;
【解决方案2】:

以下是一些更改(感谢 AndreyT):

显然,您必须更改标头才能进行编译。但即便如此,这似乎不是AndreyT 指出的标准C。尽管如此,像 gcc 这样的编译器仍然会按预期编译它并且只发出警告。同样,Microsoft 似乎并没有过于严格地解释标准:

“当结构声明是另一个结构或联合的成员时,也可以在没有声明符的情况下指定结构声明”

要使其成为标准 C,您必须将“struct yy”声明转换为定义。那么您的代码将在 C 和 C++ 中有效。为了说明发生了什么,我以一种我认为更易于理解的方式重写了它,并添加了一个关于发生了什么的小测试。

#include<stdio.h>
#include<stdlib.h>

typedef struct xx xx;
typedef struct yy yy;

struct yy{ char s; xx *p;};

struct xx{ int x; yy *q;};

int main(){
    xx test;
    test.q = (yy*)malloc(sizeof(yy));
    test.q->s = 'a';
    test.q->p = (xx*)malloc(sizeof(xx));
    test.q->p->x = 1; 
    test.q->p->q = (yy*)malloc(sizeof(yy));
    test.q->p->q->s = 'b';
    printf("s: %c\n", test.q->s);
    printf("x: %d\n", test.q->p->x);
    printf("s: %c\n", test.q->p->q->s);
    return 0;
}

您可以很容易地看到,您有一个带有指向 xx 的指针的结构 yy,而结构 xx 有一个指向 yy 的指针。这相当于在 ansi-C 中可以这样写:

#include<stdio.h>
#include<stdlib.h>

int main(){
    struct xx{
        int x;
        struct yy{
                    char s;
                    struct xx *p;
            } *q;   
            /*Here is the change to your example. You cannot have a structur 
              without a declactor inside of another structur! 
              Your version might due to compiler extensions still work*/
    };
    struct xx test;
    test.q = (struct yy*)malloc(sizeof(struct yy));
    test.q->s = 'a';
    test.q->p = (struct xx*)malloc(sizeof(struct xx));
    test.q->p->x = 1; 
    test.q->p->q = (struct yy*)malloc(sizeof(struct yy));
    test.q->p->q->s = 'b';
    printf("s: %c\n", test.q->s);
    printf("x: %d\n", test.q->p->x);
    printf("s: %c\n", test.q->p->q->s);
    return 0;
}

我用 gcc 和以下选项编译它:

gcc -ansi -pedantic -Wall -W -Wshadow -Wcast-qual -Wwrite-strings test.c -o

两种变体将具有相同的输出

s: a 
x: 1
s: b

现在,如果您想在 c++ 中做同样的事情,您的结构不必更改,但要使用内部结构,您必须调用范围解析运算符 (::),如下所示:

test.q = (xx::yy*)malloc(sizeof(xx::yy));
test.q->s = 'a';
test.q->p = (xx*)malloc(sizeof(xx));
test.q->p->x = 1; 
test.q->p->q = (xx::yy*)malloc(sizeof(xx::yy));
test.q->p->q->s = 'b';
printf("s: %c\n", test.q->s);
printf("x: %d\n", test.q->p->x);
printf("s: %c\n", test.q->p->q->s);

【讨论】:

  • 好吧,您的第二个“等效”示例进行了关键修改,使其有效 C。修改是 q 成员的声明。原代码是无效的C,你修改的是。
【解决方案3】:

C 不允许你在函数定义中嵌套类型声明。另外,为了消除关于“不声明任何东西,你应该合并类型 struct yy 和成员的声明”的警告q。以下代码使用 gcc 编译,最大警告开启:

struct xx
{
        int x;
        struct yy
        {
                char s;
                struct xx *p;
        } *q;
};

int main()
{
  return 0;
}

【讨论】:

    【解决方案4】:

    嗯,cstdio 需要被称为 stdio.h。至于结构,C++中不需要struct-keyword。

    您并没有真正定义结构成员,而是指针成员,因此在任何一种情况下它都应该工作似乎是合理的。

    【讨论】:

      【解决方案5】:

      我只是对它稍作修改和 gcc 编译器进行了测试

      struct xx {
              int x;
              struct yy { char s; struct xx *p; };
              struct yy *q;
      };
      
      int main() { return 0; }
      

      用 gcc 编译

      $ gcc test.c
      test.c:3: warning: declaration does not declare anything
      

      我编译但给出警告。由于我的 C 太生锈了,不能再说了。

      【讨论】:

        【解决方案6】:

        根据我的简短研究和 Otto 发布的错误消息,似乎 C 不允许结构成为通用名称空间容器,如 C++ 类和结构(当然,因为 C 甚至不支持类) .所以你不能在 C 中嵌套结构定义。你必须像这样在外部结构声明之外声明内部结构:

        struct yy
        {
                char s;
                struct xx *p;
        };
        struct xx
        {
            int x;
            struct yy *q;
        };
        

        我看到这些结构相互交叉引用。因此,如果这在 C 中甚至是可能的,您可能必须使用如下行预先声明后面的结构:

        struct xx;
        

        (高于其他两个声明)。

        【讨论】:

        • 在 C 中可以实现相互递归的结构。正如您所说,它们通过前向声明完成。
        猜你喜欢
        • 1970-01-01
        • 2015-07-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-12
        • 2017-02-19
        • 2015-08-14
        相关资源
        最近更新 更多