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

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

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

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

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

Очевидно, что в 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.

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

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

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

Чтобы сделать его стандартным C, вы должны превратить свою декларацию «struct yy» в определение. Тогда ваш код будет действителен в C и на C ++. Чтобы проиллюстрировать, что происходит, я переписал его, по-моему, более понятным образом и добавил немного теста на то, что происходит.

 #include #include 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 #include 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: ax: 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 не позволяет вам вставлять объявление типа внутри определения функции. Кроме того, чтобы исключить предупреждение о том, что «ничего не объявляет, вы должны объединить объявления типа struct yy и члена q . Следующие компиляции с gcc с максимальными предупреждениями:

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

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

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

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

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

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

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

 struct xx; 

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