关键字__attribute__
允许你说明变量或结构体域的特殊属性。这个关键字是跟有括在一对圆括号中的属性说明。现在给变量定义了八个属性:aligned, mode, nocommon, packed, section, transparent_union, unused
,和weak
。在特定的目标机器上定义了为变量定义了一些其它属性。其它属性可以用于函数(见 声明函数属性)和类型(见 指定类型属性)。其它q前端和末端可能定义更多的属性(见C++语言的扩展章节)。
你可能也说明属性有‘__
’开头并且跟在每一个关键字后边。这允许你在头文件中使用它们而不必担心可能有同名的宏。例如,你可以使用__aligned__
来代替aligned
。
见 属性语法,了解正确使用属性语法的细节。
aligned (对齐)这个属性以字节为单位说明一个变量或结构体域的最小对齐。例如,这个声明:
int x __attribute__ ((aligned (16))) = 0;
造成编译器在一个16字节的边界上分配全局变量x。在68040上,这可以用在和一个汇编表达式连接去访问需要16字节对齐对象的move16
指令。你也可以说明结构体域的对齐。例如,创建一个双字对齐的整型对,你可以写:struct foo { int x[2] __attribute__ ((aligned (8))); };
这是创建一个有两个成员的共用体强制共用体双字对齐的一个替换用法。它可能不能说明函数的;函数的对齐是被机器的需求所决定且不能被改变的。你不能说明一个typedef
定义的名称的对齐因为这个名字仅仅是个别名,而不是特定的类型。在前边的例子,你可以明确说明你希望编译器以给定的变量或结构体域对齐(以字节位单位)。另外一种方案,你可以省略对齐因子并且进让编译器以你为之编译的目标机器的最大有用对齐来对齐变量或域。例如,你可以写:short array[3] __attribute__ ((aligned));
无 论何时你在一个要对齐的属性说明中省略对齐因子,编译器都会自动为声明的变量或域设置对齐到你为之编译的目标机器上对 曾经对任意数据类型用过的最大对齐。这样做可以经常可以是复制动作更有效,因为编译器可以使用任何指令复制最大的内存块当执行复制到你要求这样对齐的变量 或域中或从这从中复制时。对齐属性可以仅仅增加对齐;但是你可以通过也说明packed
属性。见下边。注意这对齐属性的可行性可能被你的连接器的固有限制所限制。在许多系统上,连接器仅仅可以把变量整理和对齐到一个特定的最大对齐。(对一些连接器,所支持的最大对齐可能非常非常小。)如果你的连接器几近可以对齐变量最大8字节,那么在__attribute__
中说明aligned(16)
仍然值提供给你8字节对齐。从你的连接器文档中可以获得更多的信息。mode (模式)
这个属性位声明说明数据类型──任何类型都符合mode
模式。这有效地使你获取一个整型或浮点型的符合宽度。你可能也说明'byte
'或'__byte__
'模式来表示模式同一字节的整数一致,'word
'或'__word
'来表示一个字的整数的模式,并且'pointer
'或'__pointer__
'来表示指针的模式。
nocommon
这个属性说明要求GCC不要把放置一个变量为 "
common
"而是直接给它分配空间。如果你说明'-fno-common
'标志,GCC将对所有变量这样做。 给变量说明nocommon
属性则提供初值为零。变量可能仅在一个源文件中初始化。packed
packed
属性说明一个变量或结构体域应该有尽可能小的对齐──一个变量一字节或一个域一字节,除非你和对齐属性一起说明了一个更大的值。
- 这里是一个域
x
被packed
属性说明的结构体,所以它直接跟在a
之后:struct foo
{
char a;
int x[2] __attribute__ ((packed));
};section("段名")
通常,编译器将把对象放置在生成它的段中想data
和bss
。但是有时候你学要附加段,或者你需要一定特定的变量去出现在特殊的段中,例如去映射特殊的硬件。section
属性说明一个变量(或函数)存在一个特定的段中。例如,这个小程序使用一些说明段名:struct duart a __attribute__ ((section ("DUART_A"))) = { 0 };
struct duart b __attribute__ ((section ("DUART_B"))) = { 0 };
char stack[10000] __attribute__ ((section ("STACK"))) = { 0 };
int init_data __attribute__ ((section ("INITDATA"))) = 0;
main()
{
/* Initialize stack pointer */
init_sp (stack + sizeof (stack));
/* Initialize initialized data */
memcpy (&init_data, &data, &edata - &data);
/* Turn on the serial ports */
init_duart (&a);
init_duart (&b);
}section
属性,就像例子中那样。GCC给出一个警告或者在未初始的变量声明中忽略section
属性。你可能由于连接器的工作方式仅同一个完全初始化全局定义使用section
属性。连接器要求每个对象被定义一次,例外的是未初始化变量假定竟如common
(或bss
)段而且可以多重“定义”。你可以强制一个变量带'-fno-common
'标志初始化或nocommon
属性。一些文件格式不支持随意的段,所以section
属性不全适用于所有的平台。如果你需要映射一个完全满足的模块到一个特定的段,慎重考虑使用连接器的设备来代替。在Windows NT上, 在命名的段附加放置变量定义,这段也可以个在所有运行的可执行文件或DLL文件之间共享。例如,这个小程序通过将其放入命名的段并将该段标记位共享而定义了共享数据。int foo __attribute__((section ("shared"), shared)) = 0;
int
main()
{
/* Read and write foo. All running
copies see the same value. */
return 0;
}section
属性完全初始化全局定义是使用shared
属性,因为连接器的工作方式。看section
属性来获得更多的信息。shared
属性仅适用于Windows NT。这 个属性附属与一个共用体型的函数参数,意味着参数可能具有与共用体成员一致的任何类型,但是参数被当做共用的第一个成 员的类型传送。看 说明类型属性了解更多细节。你也能吧这个属性用在对共用体数据类型适用typedef是;这样它就可以被用在所有这个类型的函 数参数上。unused
变量有这个属性,意味着这个变量可能没有被使用。GCC将不对这个变量产生警告。weak
weak属性在 声明函数属性 已经被陈述过。model(模型名)
在M32R/D上使用这个属性去设置对象的编址能力。这个标识符模型名是small,medium或large中的一个,代表每一个代码模型。小模型对象存在与低16MB内存中(所以它们的地址可以和一个ld24指令一起装入)。中和大模型对象可能存在任何一个32位的地址空间中(编译器将形成seth/add3
指令来装入它们的地址)。说明多个属性用逗号吧它们分隔开写在一对圆括号中:例如,
'__attribute__ ((aligned (16), packed))'
。