为什么这两个结构定义编译良好:
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。
答案 0 :(得分:6)
typedef struct __attribute__((packed)) {
int a;
} bar;
VS
typedef struct {
int a;
} baz __attribute__((packed));
在第一个你说“考虑这个匿名结构,包含属性,有一个成员a。然后为这个结构创建一个别名,并命名为'bar'”。用于描述结构而不是匿名执行并且必须键入def的正常语法是
struct bar { int a; };
在第二个声明中你说“考虑这个匿名结构,它有一个成员a。然后为这个结构创建一个别名,并命名'baz who packed'”。
它不起作用,因为您尝试将该属性应用于typedef中的别名,而不是结构定义。
typedef <entity> <alias>;
对于那些建议您使用“typedef”语法来描述结构的人,我建议点击一下:)
答案 1 :(得分:1)
它在前两个实例中起作用的原因是因为__attribute__((packed))
只能应用于struct
,union
或enum
。在第一个示例中,您声明的struct
名为foo
,在第二个示例中,您声明的struct
名为bar
。在第二个示例中,typedef
将变量声明转换为类型声明。
您的第三个示例是声明一个名为baz
的变量,并尝试将其声明为已打包。由于打包信息附加到类型而不是实例,这没有任何意义,编译器会忽略它。
以下是details on how attributes work in gcc。
除非你确切知道自己在做什么,否则你真的不应该使用包装。首先,__attribute__
不是标准C.如果是gcc
扩展名,那么将无法与任何其他编译器一起使用。
另一方面,实际需要的情况很少。例如,在上面的代码中,即使在前两个实例中,它也是一个无操作,因为打包会删除成员之间的空间,并且每个struct
中只有一个成员。打包结构不是默认值的原因是因为常见数据类型在特定边界上对齐时效果更好。例如,如果在4的倍数的内存位置上对齐,则对int
的访问将更好。请参阅the wiki entry on data structure alignment for more information。
答案 2 :(得分:1)
关键字__attribute__((packed))
适用于 struct 。
在
typedef struct {
int a;
} baz __attribute__((packed));
typedef 将 baz 与结构相关联 - 属性随后出现,并且不适用于任何内容 - gcc忽略它。要解决此问题,请允许 typedef 关联整个 struct 声明,包括属性,方法是在 baz 之后放置 baz 属性:
typedef struct {
int a;
} __attribute__((packed)) baz;
在第二个示例中, struct 声明是错误的
struct qux __attribute__((packed)) {
int a;
}
quz 应出现在属性:
之后struct __attribute__((packed)) qux {
int a;
}
通常最好让编译器优化结构,并以CPU更有效地处理它们的方式对齐内存中的内部元素。
然而,在构建必须打包的数据结构时,打包结构可能很重要,以便例如应对驱动程序需求。
答案 3 :(得分:0)
这是一个相当奇怪的问题,因为它在手册中都有很好的解释。但是,对于它没有任何武断,你只是没有探索完全使用这个内置关键字:
__attribute__(())
是一个通用的gcc扩展。有函数属性,类型属性和变量属性。
您放置__attribute__
一词的位置决定了它适用的内容。您可能在给定的声明中有几个__attribute__
,因此,为了更容易进行内部解析,使其中某些语法不可接受并不是任意的。