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

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

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

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

Ответ 1

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

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

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

Добавлено: Язык C запрещает объявление типов структур внутри других структур без объявления этого типа. Таким образом, вы struct yy декларация является незаконным в C и будет выдавать диагностическое сообщение компилятора. Если вы хотите, чтобы ваш код стал законным как на C, так и на С++, вам нужно было бы объединить объявление struct yy с некоторым объявлением члена данных. В вашем случае это может быть указатель q:

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

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

Ответ 2

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

Очевидно, вам нужно изменить заголовки, чтобы сделать эту компиляцию. Но даже тогда это, похоже, не является стандартным C как AndreyT. Тем не менее некоторые компиляторы, такие как gcc, все еще собирают его, как ожидалось, и только выдает предупреждение. Аналогично, Microsoft, похоже, не слишком интерпретирует стандарт:

"Объявления структуры также могут быть указаны без декларатора, когда они являются членами другой структуры или объединения"

Чтобы сделать его стандартным C, вы должны превратить свою декларацию "struct yy" в определение. Тогда ваш код будет действителен в 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;
}

Вы можете легко видеть, что у вас есть struct yy с указателем на xx, а struct 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

Теперь, если вы хотите сделать то же самое в С++, ваша структура не должна меняться, но для использования внутренней структуры вы должны вызвать оператор разрешения области (::) следующим образом:

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);

Ответ 3

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

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

int main()
{
  return 0;
}

Ответ 4

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

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

Ответ 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

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

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

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

struct xx;

(выше обеих других объявлений).