6

为什么这两个结构定义编译得很好:

struct foo {
    int a;
} __attribute__((packed));

typedef struct __attribute__((packed)) {
    int a;
} bar;

虽然这个给出了警告:

typedef struct {
    int a;
} baz __attribute__((packed));


warning: ‘packed’ attribute ignored [-Wattributes]

这给出了一个错误和警告:

typedef struct qux __attribute__((packed)) {
    int a;
} qux;

error: expected identifier or ‘(’ before ‘{’ token
warning: data definition has no type or storage class [enabled by default]

作为一个新手 C 程序员,最后两个定义不起作用的事实对于语言设计者/编译器编写者来说似乎是一个相当随意的选择。是否有一个原因?我正在使用 gcc 4.7.3。

4

4 回答 4

7
typedef struct __attribute__((packed)) {
    int a;
} bar;

对比

typedef struct {
    int a;
} baz __attribute__((packed));

在第一个中,您说“考虑这个匿名结构,该结构具有打包的属性,它有一个成员 a。然后为这个结构创建一个别名,并命名那个 'bar'”。描述结构的正常语法而不是匿名进行并且必须 typedef 它是

struct bar { int a; };

在第二个声明中,您说“考虑这个匿名结构,它有一个成员 a。然后为这个结构创建一个别名,并将其命名为 'baz who is packed'”。

它不起作用,因为您试图将属性应用于 typedef 中的别名,而不是结构定义。

typedef <entity> <alias>;

我建议对建议您使用“typedef”语法来描述结构的人进行打击:)

于 2013-06-02T04:58:52.067 回答
1

它在前两个实例中起作用的原因是因为__attribute__((packed))只能应用于astruct或。在第一个示例中,您声明了一个被调用,在第二个示例中您声明了一个被调用。在第二个示例中,将变量声明转换为类型声明。unionenumstructfoostructbartypedef

您的第三个示例是声明一个名为的变量baz并尝试将其声明为已打包。由于打包信息附加到类型而不是实例,这没有意义,编译器会忽略它。

以下是有关属性如何在 gcc中工作的详细信息。

除非您确切知道自己在做什么,否则您真的不应该使用 packed。一方面,__attribute__它不是标准的 C。If 是一个gcc扩展,因此不能与任何其他编译器一起使用。

另一方面,很少有实际需要它的情况。例如,在您上面的代码中,即使在前两个实例中它也是无操作的,因为打包删除了成员之间的空间,并且每个struct. 打包结构不是默认设置的原因是,普通数据类型在特定边界上对齐时效果更好。例如,int如果在一个 4 的倍数的内存位置上对齐,对 an 的访问将执行得更好。有关详细信息,请参阅有关数据结构对齐的 wiki 条目

于 2013-06-02T03:55:25.113 回答
1

该关键字__attribute__((packed))适用于struct

typedef struct {
    int a;
} baz __attribute__((packed));

typedef将baz与 struct相关联——属性紧随其后,并适用于任何内容——gcc 忽略它。为了解决这个问题,允许typedef通过将baz放在属性之后来关联整个结构声明,包括属性

typedef struct {
    int a;
} __attribute__((packed)) baz;

在第二个例子中,结构声明是错误的

struct qux __attribute__((packed)) {
    int a;
} 

因为quz应该出现在属性之后:

struct __attribute__((packed)) qux {
    int a;
} 

通常最好让编译器优化结构并以 CPU 更有效地处理它们的方式对齐内存中的内部元素。

然而,在构建必须打包的数据结构时,打包结构有时可能很重要,以便应对例如驱动程序的需求。

于 2013-06-02T03:55:49.903 回答
0

这是一个相当奇怪的问题,因为手册中对此进行了很好的解释。但是,它没有任何随意性,您只是没有探索这个内置关键字的完整用法:

__attribute__(())是一个通用的 gcc 扩展。有函数属性、类型属性和变量属性。

您放置单词的位置__attribute__决定了它适用于什么。您可能__attribute__在给定的声明中包含多个 s,因此将其中一些在语法上不可接受以简化内部解析并不是任意的。

于 2013-06-02T04:02:13.463 回答