LCC:初始化包含结构的结构?

发布于 2024-12-02 12:50:20 字数 891 浏览 1 评论 0原文

以下代码片段在使用 gcc 的 Mac OS X 上编译得很好,但在使用 lcc-win32 的 Windows 上编译失败:

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 枚举失败?

The following code snippet compiles just fine on Mac OS X with gcc, but fails to compile on Windows with 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 };

And gives this error:

found 'struct Bar' expected 'int'

I can 'overcome' this by initializing the struct this way:

Foo instance = { barOne.age, barOne.height, barTwo.age, barTwo.height };

So, I understand what's going on... but I feel like this makes my code a lot more complex (I need to understand the implementation and layout of the other structs I'm using, instead of simply consuming them - and if that layout changes, I have to spider that change out to anyone else using the struct).

I'm wondering if LCC is being either "more strict" (adhering to some standard) or "more dumb" (the compiler is too dumb to handle this situation).

Thanks.

Also, please see my other LCC-Win32 question: LCC: Forward Declaration of Typedef'd Enum Failing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

淡淡的优雅 2024-12-09 12:50:20

如所写:

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

代码应该无法在任何地方编译(特别是在带有 GCC 4.6.0 的 MacOS X 10.7.1 上失败),并出现这些错误(以及其他一些错误):

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 初始化

¶13 具有自动存储持续时间的结构或联合对象的初始值设定项应为
如下所述的初始化列表,或具有兼容的单个表达式
结构或联合类型。在后一种情况下,对象的初始值,包括
未命名的成员,是表达式的成员。

考虑函数的上下文(此代码在 GCC 设置为 fussy 的情况下编译正常):

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

从表面上看,在我看来 barOnebarTwo 不是单个表达式。然而,该标准接着说:

¶16 否则,具有聚合或联合类型的对象的初始值设定项应为元素或命名成员的用大括号括起来的初始值设定项列表。

如果聚合必须用大括号括起来,那么这样写就可以了:

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没有有效处理案件。有争议的是,这需要对 C 标准的第 6.7.8 节进行完整的解析,并且我没有提供所有材料(在开始示例之前,请参阅第 23 节)。

As written:

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

the code should fail to compile everywhere (and specifically fails on MacOS X 10.7.1 with GCC 4.6.0) with these errors (plus some others):

xx.c:4: error: field ‘barOne’ has incomplete type
xx.c:4: error: field ‘barTwo’ has incomplete type

This is because you try to use Bar before it is defined. Reverse the order of the structure definitions, and fix the syntax errors in Bar (comma should be semi-colon; missing semi-colon), and then (finally) it does compile on MacOS X.

What does the standard say about using structures as initializers?

§6.7.8 Initialization

¶13 The initializer for a structure or union object that has automatic storage duration shall be
either an initializer list as described below, or a single expression that has compatible
structure or union type. In the latter case, the initial value of the object, including
unnamed members, is that of the expression.

Consider the context of a function (this code compiles OK with GCC set fussy):

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

Superficially, it looks to me like barOne and barTwo are not single expressions. However, the standard goes on to say:

¶16 Otherwise, the initializer for an object that has aggregate or union type shall be a brace-enclosed list of initializers for the elements or named members.

If the aggregates had to be enclosed braces, then writing this would work:

Foo instance = { { barOne }, { barTwo } };

GCC emphatically rejects this construct, though.

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’

On the whole, I'm inclined to trust GCC's judgement and point the finger at LCC not handling a case validly. Disputing that will require a complete parsing of §6.7.8 of the C standard, and I've not provided all the material (it goes to ¶23 before starting on the examples).

涫野音 2024-12-09 12:50:20

有时,它被称为“Little C 编译器”并不是无缘无故的。它可以处理大多数事情,但为了节省空间和时间,在这些情况下通常会更严格。实现看起来简单的东西通常不是在编译器中实现的。要么是 LCC 从未更新来处理这些情况。使用 LCC 而不是 Borland、MSVC++、Cygin/MingW32 gcc 是否有具体原因?

Well it's not called the Little C Compiler sometimes for nothing. It can handle most things but to save space and time it will generally be stricter in these cases. Implementing something that looks simple usually isn't in a compiler. Either that or LCC was just never updated to handle these situations. Is there a specific reason for using LCC instead of Borland, MSVC++, Cygin/MingW32 gcc?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文