LCC: Инициализация структур, содержащих структуры?
Следующий фрагмент кода прекрасно компилируется в Mac OS X с gcc, но не компилируется в Windows с lcc-win32:
typedef struct Foo Foo;
typedef struct Bar Bar;
struct Bar { int age; int height; };
struct Foo { Bar barOne; Bar barTwo; };
// Elsewhere, in some function:
Bar barOne = { 2, 4 };
Bar barTwo = { 6, 8 };
Foo instance = { barOne, barTwo };
И дает эту ошибку:
нашел "struct Bar" ожидаемый "int"
Я могу "преодолеть" это, инициализируя структуру следующим образом:
Foo instance = { barOne.age, barOne.height, barTwo.age, barTwo.height };
Итак, я понимаю, что происходит... но я чувствую, что это делает мой код намного более сложным (мне нужно понять реализацию и компоновку других структур, которые я использую, вместо того, чтобы просто потреблять их - и если эта компоновка изменения, я должен паук, который изменить кому-либо еще с помощью структуры).
Мне интересно, является ли LCC "более строгим" (придерживающимся некоторого стандарта) или "более тупым" (компилятор слишком туп, чтобы справиться с этой ситуацией).
Благодарю.
Кроме того, см. Мой другой вопрос LCC-Win32: LCC: предварительная декларация Typedef'd Enum Failing?
2 ответа
Ну, это не называется Little C Compiler иногда даром. Он может справиться с большинством вещей, но для экономии места и времени в таких случаях он будет в целом более строгим. Реализация чего-то, что выглядит просто, обычно не в компиляторе. Либо это, либо LCC просто никогда не обновлялись, чтобы справиться с этими ситуациями. Есть ли конкретная причина для использования LCC вместо Borland, MSVC++, Cygin/MingW32 gcc?
Как написано:
typedef struct Foo Foo;
typedef struct Bar Bar;
struct Foo { Bar barOne; Bar barTwo; };
struct Bar { int age, int height };
// Elsewhere, in some function:
Bar barOne = { 2, 4 };
Bar barTwo = { 6, 8 };
Foo instance = { barOne, barTwo };
код не должен компилироваться везде (и, в частности, не работает на MacOS X 10.7.1 с GCC 4.6.0) с этими ошибками (плюс некоторые другие):
xx.c:4: error: field ‘barOne’ has incomplete type
xx.c:4: error: field ‘barTwo’ has incomplete type
Это потому, что вы пытаетесь использовать Bar
прежде чем это будет определено. Поменяйте порядок определений структуры и исправьте синтаксические ошибки в Bar (запятая должна быть точкой с запятой; пропущена точка с запятой), а затем (наконец) она скомпилируется в MacOS X.
Что стандарт говорит об использовании структур в качестве инициализаторов?
§6.7.8 Инициализация
The13 Инициализатор для структуры или объекта объединения, который имеет автоматическую продолжительность хранения, должен быть либо списком инициализатора, как описано ниже, либо единственным выражением, которое имеет совместимую структуру или тип объединения. В последнем случае начальное значение объекта, включая неназванные члены, является значением выражения.
Рассмотрим контекст функции (этот код компилируется нормально с установленным GCC суетой):
typedef struct Foo Foo;
typedef struct Bar Bar;
struct Bar { int age; int height; };
struct Foo { Bar barOne; Bar barTwo; };
void somefunction(void)
{
Bar barOne = { 2, 4 };
Bar barTwo = { 6, 8 };
Foo instance = { barOne, barTwo };
}
Внешне это выглядит как barOne
а также barTwo
не одиночные выражения. Тем не менее, стандарт продолжает:
Other16 В противном случае инициализатор для объекта, который имеет агрегатный или объединенный тип, должен быть заключенным в скобки списком инициализаторов для элементов или именованных членов.
Если агрегаты должны быть заключены в фигурные скобки, то написать это будет работать:
Foo instance = { { barOne }, { barTwo } };
GCC категорически отвергает эту конструкцию, хотя.
i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)
/usr/bin/gcc -g -std=c99 -Wall -Wextra -Wmissing-prototypes -c xx.c
xx.c:8: warning: no previous prototype for ‘somefunction’
xx.c: In function ‘somefunction’:
xx.c:11: error: incompatible types in initialization
xx.c:11: warning: missing initializer
xx.c:11: warning: (near initialization for ‘instance.barOne.age’)
xx.c:11: error: incompatible types in initialization
xx.c:11: warning: missing initializer
xx.c:11: warning: (near initialization for ‘instance.barTwo.age’)
xx.c:11: warning: missing initializer
xx.c:11: warning: (near initialization for ‘instance.barOne’)
xx.c:11: warning: unused variable ‘instance’
В целом, я склонен доверять решению GCC и указывать пальцем на то, что LCC не рассматривает дело должным образом. Диспуты, которые потребуют полного разбора §6.7.8 стандарта C, и я не предоставил весь материал (он идет до ¶23, прежде чем начинать на примерах).