Вложенные структуры - PullRequest
       28

Вложенные структуры

11 голосов
/ 29 ноября 2009

Следующий код компилируется на компиляторе C ++.

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

Будет ли какая-либо разница в поведении при компиляции с компилятором C?
то есть будет ли ошибка компилятора?

Ответы [ 6 ]

17 голосов
/ 29 ноября 2009

Код в вашем посте явно неполный, просто декларации, поэтому трудно сказать что-либо убедительное.

Очевидное отличие состоит в том, что в C ++ внутренний тип структуры будет членом внешнего типа структуры, в то время как в языке C оба типа структуры будут членами одной и той же (охватывающей) области видимости. (Кстати, вы намеревались объявить их локально в main?).

Другими словами, в C ++ следующий код должен ссылаться на структуры как xx и xx::yy, тогда как в C они будут просто xx и yy. Это означает, что дальнейший код будет выглядеть по-разному для 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.

4 голосов
/ 29 ноября 2009

Вот некоторые изменения (спасибо AndreyT):

Очевидно, что вы должны изменить заголовки, чтобы сделать эту компиляцию. Но даже тогда, похоже, это не стандартный C, как указывало AndreyT . Тем не менее, некоторые компиляторы, такие как 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;
}

Вы можете легко увидеть, что у вас есть структура yy с указателем на xx, а структура 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);
2 голосов
/ 30 ноября 2009

C не позволяет вам вкладывать объявление типа в определение функции. Кроме того, чтобы исключить предупреждение о том, что «ничего не объявляется», вы должны объединить объявления типа struct yy и member q. Следующие компиляции с gcc с максимальным количеством предупреждений:

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

int main()
{
  return 0;
}
0 голосов
/ 29 ноября 2009

На основании моего краткого исследования и сообщения об ошибке, опубликованного Отто, выясняется, что C не позволяет структурам быть контейнерами пространства имен общего назначения, такими как классы и структуры C ++ (естественно, потому что C даже не поддерживает классы) , Таким образом, вы не можете вложить определения структуры в C. Вы должны объявить внутреннюю структуру вне объявления внешней структуры следующим образом:

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

Я вижу, что структуры перекрестно ссылаются друг на друга. Поэтому, если это даже возможно в C, вам, возможно, придется предварительно объявить более позднюю структуру с помощью строки вроде:

struct xx;

(выше обеих других деклараций).

0 голосов
/ 29 ноября 2009

Я только что протестировал его с небольшими изменениями и компилятором 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 слишком ржавый, больше ничего не могу сказать.

0 голосов
/ 29 ноября 2009

Ну, cstdio должен называться stdio.h. Что касается структуры, ключевое слово struct не требуется в C ++.

Вы на самом деле не определяете элементы структуры, а только элементы-указатели, поэтому кажется вероятным, что это будет работать в любом случае.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...