ARM 编译器 armclang 参考指南 - 特定于编译器的函数、变量和类型属性

第 3 章 特定于编译器的函数、变量和类型属性

总结了作为 C 和 C++ 标准扩展的特定于编译器的函数、变量和类型属性。
它包含以下部分:

3.1 功能属性。
3.2 __attribute__((always_inline)) 函数属性。
3.3 __attribute__((cmse_nonsecure_call)) 函数属性。
3.4 __attribute__((cmse_nonsecure_entry)) 函数属性。
3.5 __attribute__((const)) 函数属性。
3.6 __attribute__((constructor[(priority)])) 函数属性。
3.7 __attribute__((format_arg(string-index))) 函数属性。
3.8 __attribute__((interrupt("type"))) 函数属性。
3.9 __attribute__((malloc)) 函数属性。
3.10 __attribute__((naked)) 函数属性。
3.11 __attribute__((noinline)) 函数属性。
3.12 __attribute__((nonnull)) 函数属性。
3.13 __attribute__((noreturn)) 函数属性。
3.14 __attribute__((nothrow)) 函数属性。
3.15 __attribute__((pcs("calling_convention"))) 函数属性。
3.16 __attribute__((pure)) 函数属性。
3.17 __attribute__((section("name"))) 函数属性。
3.18 __attribute__((used)) 函数属性。
3.19 __attribute__((unused)) 函数属性。
3.20 __attribute__((value_in_regs)) 函数属性。
3.21 __attribute__((visibility("visibility_type"))) 函数属性。
3.22 __attribute__((weak)) 函数属性。
3.23 __attribute__((weakref("target"))) 函数属性。
3.24 类型属性。
3.25 __attribute__((aligned)) 类型属性。
3.26 __attribute__((packed)) 类型属性。
3.27 __attribute__((transparent_union)) 类型属性。
3.28 变量属性。
3.29 __attribute__((alias)) 变量属性。
3.30 __attribute__((aligned)) 变量属性。
3.31 __attribute__((deprecated)) 变量属性。
3.32 __attribute__((packed)) 变量属性。
3.33 __attribute__((section("name"))) 变量属性。
3.34 __attribute__((used)) 变量属性。
3.35 __attribute__((unused)) 变量属性。
3.36 __attribute__((weak)) 变量属性。
3.37 __attribute__((weakref("target"))) 变量属性。

3.1 函数属性

__attribute__ 关键字使您能够指定变量、结构字段、函数和类型的特殊属性。
关键字格式为以下之一:

__attribute__((attribute1, attribute2, ...))
__attribute__((__attribute1__, __attribute2__, ...))

 例如:

int my_function(int b) __attribute__((const));
static int my_variable __attribute__((__unused__));

下表总结了可用的函数属性。
表 3-1 编译器支持的函数属性及其等价物

Function attributeNon-attribute equivalent
__attribute__((alias))-
__attribute__((always_inline))-
__attribute__((const))-
__attribute__((constructor[(priority)]))-
__attribute__((deprecated))-
__attribute__((destructor[(priority)]))-
__attribute__((format_arg(string-index)))-
__attribute__((malloc))-
__attribute__((noinline))__declspec(noinline)
__attribute__((nomerge))-
__attribute__((nonnull))-
__attribute__((noreturn))__declspec(noreturn))
__attribute__((nothrow))__delspec(nothrow)
__attribute__((notailcall))-
__attribute__((pcs("calling_convention")))-
__attribute__((pure))-
__attribute__((section("name")))-
__attribute__((unused))-
__attribute__((used))-
__attribute__((visibility("visibility_type")))-
__attribute__((weak))-
__attribute__((weakref("target")))-

用法

您可以在声明、定义或两者中设置这些函数属性。例如:

void AddGlobals(void) __attribute__((always_inline));
__attribute__((always_inline)) void AddGlobals(void) {...}

当函数属性发生冲突时,编译器会使用更安全或更强的属性。例如,__attribute__((used)) 比 __attribute__((unused)) 更安全,而 __attribute__((noinline)) 比 __attribute__((always_inline)) 更安全。

3.2 __attribute__((always_inline)) 函数属性

该函数属性表示必须内联函数。
编译器尝试内联函数,而不考虑函数的特征。
在某些情况下,编译器可能会选择忽略 __attribute__((always_inline)),而不是内联函数。例如:递归函数永远不会内联到自身中。

使用 alloca() 的函数可能不会被内联。

示例

static int max(int x, int y) __attribute__((always_inline));
static int max(int x, int y)
{
    return x > y ? x : y; // always inline if possible
}

3.3 __attribute__((cmse_nonsecure_call)) 函数属性

声明非安全函数类型

对将状态从安全切换到非安全的函数的调用称为非安全函数调用。非安全函数调用只能通过函数指针发生。这是将安全代码和非安全代码分离为单独的可执行文件的结果。
非安全函数类型只能用作指针的基本类型。

示例

#include <arm_cmse.h>
typedef void __attribute__((cmse_nonsecure_call)) nsfunc(void);

void default_callback(void) { … }

// fp can point to a secure function or a non-secure function
nsfunc *fp = (nsfunc *) default_callback;   // secure function pointer

void __attribute__((cmse_nonsecure_entry)) entry(nsfunc *callback) {
    fp = cmse_nsfptr_create(callback);      // non-secure function pointer
}

void call_callback(void) {
    if (cmse_is_nsfptr(fp)){
	   fp();           // non-secure function call
    }
    else {
        ((void (*)(void)) fp)();           // normal function call
    }
}

3.4 __attribute__((cmse_nonsecure_entry)) 函数属性

声明可以从非安全状态或安全状态调用的入口函数。
语法

C 链接:

void __attribute__((cmse_nonsecure_entry)) entry_func(int val)

C++ 链接:

extern "C" void __attribute__((cmse_nonsecure_entry)) entry_func(int val)

注意:

使用目标的最大功能编译安全代码。例如,如果您在没有 FPU 的情况下进行编译,则当从声明为 __attribute__((cmse_nonsecure_entry)) 的函数返回时,安全函数不会清除浮点寄存器。因此,这些函数可能会泄露敏感数据。

示例

#include <arm_cmse.h>
void __attribute__((cmse_nonsecure_entry)) entry_func(int val) {
  int state = cmse_nonsecure_caller();

  if (state)
  { // called from non-secure
    // do non-secure work
    ...
  } else
  { // called from within secure
    // do secure work
    ...
  }
}

3.5 __attribute__((const)) 函数属性

const 函数属性指定一个函数只检查它的参数,除了返回值之外没有任何作用。也就是说,该函数不会读取或修改任何全局内存。
如果已知函数仅对其参数进行操作,则可以对其进行常见的子表达式消除和循环优化。
此属性比 __attribute__((pure)) 更严格,因为不允许函数读取全局内存。

示例

#include <stdio.h>

// __attribute__((const)) functions do not read or modify any global memory
int my_double(int b) __attribute__((const));
int my_double(int b) {
  return b*2;
}

int main(void) {
    int i;
    int result;
    for (i = 0; i < 10; i++)
    {
       result = my_double(i);
       printf (" i = %d ; result = %d \n", i, result);
    }
}

3.6 __attribute__((constructor[(priority)])) 函数属性

该属性导致与其关联的函数在进入main() 之前被自动调用。
语法

__attribute__((constructor[(priority)]))

其中,priority 是表示优先级的可选整数值。具有低整数值的构造函数在具有高整数值的构造函数之前运行。具有优先级的构造函数在没有优先级的构造函数之前运行。
不超过 100 的优先级值保留供内部使用。如果使用这些值,编译器会发出警告。
用法

您可以将此属性用于启动或初始化代码。
示例

在下面的示例中,构造函数在执行进入 main() 之前被调用,按照指定的顺序:

#include <stdio.h>
void my_constructor1(void) __attribute__((constructor));
void my_constructor2(void) __attribute__((constructor(102)));
void my_constructor3(void) __attribute__((constructor(103)));
void my_constructor1(void) /* This is the 3rd constructor */
{                        /* function to be called */
    printf("Called my_constructor1()\n");
}
void my_constructor2(void) /* This is the 1st constructor */
{                         /* function to be called */
    printf("Called my_constructor2()\n");
}
void my_constructor3(void) /* This is the 2nd constructor */
{                         /* function to be called */
    printf("Called my_constructor3()\n");
}
int main(void)
{
    printf("Called main()\n");
}

此示例产生以下输出:

Called my_constructor2()
Called my_constructor3()
Called my_constructor1()
Called main()

3.7 __attribute__((format_arg(string-index))) 函数属性

该属性指定函数将格式字符串作为参数。格式字符串可以包含类型占位符,这些占位符旨在传递给 printf 样式的函数,例如 printf()、scanf()、strftime() 或 strfmon()。
当函数的输出用于调用 printf 样式函数时,此属性使编译器对指定参数执行占位符类型检查。
语法

__attribute__((format_arg(string-index)))

其中 string-index 指定作为格式字符串参数的参数(从 1 开始)。
示例

下面的示例声明了两个函数,myFormatText1() 和 myFormatText2(),它们为 printf() 提供格式字符串。
第一个函数 myFormatText1() 没有指定 format_arg 属性。编译器不检查 printf 参数的类型与格式字符串的一致性。
第二个函数 myFormatText2() 指定 format_arg 属性。在随后对 printf() 的调用中,编译器检查提供的参数 a 和 b 的类型是否与 myFormatText2() 的格式字符串参数一致。当在预期 int 的地方提供浮点数时,编译器会产生警告。

#include <stdio.h>

// Function used by printf. No format type checking.
extern char *myFormatText1 (const char *);

// Function used by printf. Format type checking on argument 1.
extern char *myFormatText2 (const char *) __attribute__((format_arg(1)));


int main(void) {
  int a;
  float b;

  a = 5;
  b = 9.099999;

  printf(myFormatText1("Here is an integer: %d\n"), a); // No type checking. Types match anyway.
  printf(myFormatText1("Here is an integer: %d\n"), b); // No type checking. Type mismatch, but no warning                            

  printf(myFormatText2("Here is an integer: %d\n"), a); // Type checking. Types match.
  printf(myFormatText2("Here is an integer: %d\n"), b); // Type checking. Type mismatch results in warning
}

$ armclang --target=aarch64-arm-none-eabi -mcpu=cortex-a53 -c format_arg_test.c 
format_arg_test.c:21:53: warning: format specifies type 'int' but the argument has type 'float' [-Wformat]
  printf(myFormatText2("Here is an integer: %d\n"), b); // Type checking. Type mismatch results in warning
                                            ~~      ^
                                            %f
1 warning generated.

3.8 __attribute__((interrupt("type"))) 函数属性

GNU 风格的中断属性指示编译器以适合用作异常处理程序的方式生成函数。
语法

__attribute__((interrupt("type")))

其中类型是以下之一:

  • IRQ.
  • FIQ.
  • SWI.
  • ABORT.
  • UNDEF.

用法

中断属性影响函数的代码生成如下:

如果函数是 AAPCS,则堆栈在进入时重新对齐为 8 个字节。

对于不基于 M 配置文件的处理器,保留所有处理器寄存器,而不仅仅是 AAPCS 需要保留的寄存器。不保留浮点寄存器。
对于不基于 M 配置文件的处理器,该函数使用在体系结构上定义为从异常返回的指令返回。
限制

使用 __attribute__((interrupt("type"))) 函数时:

函数不能使用参数或返回值。

这些函数与-frwpi 不兼容。

注意:

在 ARMv6-M、ARMv7-M 和 ARMv8-M 中,架构异常处理机制会保留所有处理器寄存器,标准函数返回可能会导致异常返回。因此,指定中断属性不会影响编译输出的行为。但是,ARM 建议在异常处理程序上使用中断属性,以便更清晰和更轻松地进行软件移植。
注意:

对于支持 A32 和 T32 指令的体系结构,使用中断属性指定的函数根据编译选项指定 ARM 还是 Thumb 编译为 A32 或 T32 代码。
对于仅限 Thumb 的体系结构,例如 ARMv6-M,使用中断属性指定的函数编译为 T32 代码。
中断属性不适用于 A64 代码。

3.9 __attribute__((malloc)) 函数属性

该函数属性表示该函数可以被视为malloc,编译器可以执行相关的优化。

示例

void * foo(int b) __attribute__((malloc));

3.10 __attribute__((naked)) 函数属性

该属性告诉编译器该函数是一个嵌入式汇编函数。您可以使用 __asm 语句完全用汇编代码编写函数的主体。
编译器不会为具有 __attribute__((naked)) 的函数生成序言和尾声序列。
编译器仅支持 __attribute__((naked)) 函数中的基本 __asm 语句。使用扩展程序集、参数引用或将 C 代码与 __asm 语句混合可能无法可靠地工作。

示例 3-1 示例

__attribute__((naked)) int add(int i, int j); /* Declaring a function with __attribute__((naked)). */

__attribute__((naked)) int add(int i, int j)
{
    __asm("ADD r0, r1, #1"); /* Basic assembler statements are supported. */

/*  Parameter references are not supported inside naked functions: */
/*  __asm (
    "ADD r0, %[input_i], %[input_j]"       /* Assembler statement with parameter references */
    :                                      /* Output operand parameter */
    : [input_i] "r" (i), [input_j] "r" (j) /* Input operand parameter */
    );
*/

/*  Mixing C code is not supported inside naked functions: */
/*  int res = 0;
    return res; 
*/

}

3.11 __attribute__((noinline)) 函数属性

该属性抑制函数在函数调用点的内联。
__attribute__((noinline)) 也可以应用于常量数据,以防止编译器将值用于优化目的,而不影响其在对象中的位置。这是一个可用于可修补常量的功能,即后来修补为不同值的数据。在需要常量值的上下文中尝试使用此类常量是错误的。

示例

/* Prevent y being used for optimization */
const int y = 5 __attribute__((noinline));
/* Suppress inlining of foo() wherever foo() is called */
int foo(void) __attribute__((noinline));

3.12 __attribute__((nonnull)) 函数属性

此函数属性指定不应为空指针的函数参数。这使编译器能够在遇到此类参数时生成警告。
语法

__attribute__((nonnull[(arg-index, ...)]))

其中 [(arg-index, ...)] 表示可选参数索引列表。
如果未指定参数索引列表,则所有指针参数都标记为非空。
注意:

参数索引列表是从 1 开始的,而不是从 0 开始的。
示例

以下声明是等效的:

void * my_memcpy (void *dest, const void *src, size_t len) __attribute__((nonnull (1, 2)));
void * my_memcpy (void *dest, const void *src, size_t len) __attribute__((nonnull));

3.13 __attribute__((noreturn)) 函数属性

该属性断言函数永远不会返回。
用法

使用此属性可降低调用从不返回的函数的成本,例如 exit()。如果 noreturn 函数返回其调用者,则行为未定义。
限制

调用 noreturn 函数时不保留返回地址。这限制了调试器显示调用堆栈的能力。

3.14 __attribute__((nothrow)) 函数属性

该属性断言对函数的调用永远不会导致从被调用者发送到调用者的 C++ 异常。
ARM 库头文件会自动将此限定符添加到 C 函数的声明中,根据 ISO C 标准,这些函数永远不会引发异常。但是,为 C 库函数生成的展开表存在一些限制,这些函数可能会在 C++ 上下文中引发异常,例如 bsearch 和 qsort。
如果编译器知道一个函数永远不会抛出异常,它可能会为该函数的调用者生成更小的异常处理表。

3.15 __attribute__((pcs("calling_convention"))) 函数属性

该函数属性指定硬件浮点目标的调用约定。
语法

__attribute__((pcs("calling_convention")))

call_convention 是以下之一:

aapcs

uses integer registers.

aapcs-vfp

uses floating-point registers.

示例

double foo (float) __attribute__((pcs("aapcs")));

3.16 __attribute__((pure)) 函数属性

很多函数除了返回一个值外没有任何作用,它们的返回值只取决于参数和全局变量。此类功能可能会受到数据流分析的影响,并且可能会被淘汰。
示例

int bar(int b) __attribute__((pure));
int bar(int b)
{
    return b++;
}
int foo(int b)
{
    int aLocal=0;
    aLocal += bar(b);
    aLocal += bar(b);
    return 0;
}

此示例中对 bar 的调用可能会被取消,因为它的结果未被使用。

3.17 __attribute__((section("name"))) 函数属性

section 函数属性使您可以将代码放置在图像的不同部分。
示例

在以下示例中,函数 foo 被放入名为 new_section 而不是 .text 的 RO 节中。

int foo(void) __attribute__((section ("new_section")));
int foo(void)
{
  return 2;
}

注意:

部分名称必须是唯一的。您不能对不同的部分类型使用相同的部分名称。如果您对不同的节类型使用相同的节名,则编译器会将这些节合并为一个,并为该节提供首先分配给该节的函数或变量的类型。

3.18 __attribute__((used)) 函数属性

该函数属性通知编译器静态函数将保留在目标文件中,即使它未被引用。
标有 __attribute__((used)) 的函数在目标文件中被标记,以避免链接器将未使用的部分删除。
注意:

静态变量也可以通过使用 __attribute__((used)) 标记为已使用。

示例

static int lose_this(int);
static int keep_this(int) __attribute__((used));     // retained in object file
static int keep_this_too(int) __attribute__((used)); // retained in object file

3.19 __attribute__((unused)) 函数属性

未引用的函数属性可防止编译器在未引用该函数时生成警告。这不会改变未使用的函数删除过程的行为。
注意:

默认情况下,编译器不会警告未使用的函数。使用 -Wunused-function 专门启用此警告,或使用包含的 -W 值,例如 -Wall。
__attribute__((unused)) 属性如果您通常想要警告未使用的函数,但想要禁止针对特定函数集的警告,则该属性可能很有用。
示例

tatic int unused_no_warning(int b) __attribute__((unused));
static int unused_no_warning(int b)
{
  return b++;
}

static int unused_with_warning(int b);
static int unused_with_warning(int b)
{
  return b++;
}

使用 -Wall 编译此示例会导致以下警告:

armclang --target=aarch64-arm-none-eabi -c test.c -Wall
test.c:10:12: warning: unused function 'unused_with_warning' [-Wunused-function]
static int unused_with_warning(int b)
           ^
1 warning generated.

3.20 __attribute__((value_in_regs)) 函数属性

value_in_regs 函数属性与返回类型为结构的函数兼容。它改变了函数的调用约定,使返回的结构存储在参数寄存器中,而不是使用隐式指针参数写入内存。
注意:

使用 __attribute__((value_in_regs)) 时,调用约定仅使用整数寄存器。
语法

__attribute__((value_in_regs)) return-type function-name([argument-list]);

其中:

return-type 是返回结构的类型,它符合如下所述的某些限制。

用法

声明函数 __attribute__((value_in_regs)) 在调用返回多个结果的函数时很有用。
限制

当以 AArch32 为目标时,返回的结构最多可以有 16 个字节,以适应四个 32 位参数寄存器。以 AArch64 为目标时,返回的结构最多可以有 64 个字节,以适应八个 64 位参数寄存器。如果由 __attribute__((value_in_regs)) 限定的函数返回的结构太大,编译器会产生错误。
返回结构的每个字段必须恰好占用一个或两个整数寄存器,并且不得要求结构的隐式填充。其他任何东西,包括位域,都是不兼容的。嵌套结构的允许具有相同的限制,即作为一个整体的嵌套结构及其各个成员必须恰好占用一个或两个整数寄存器。
如果联合至少有一个最大大小的成员恰好占用一个或两个整数寄存器,则它们是允许的。联合中的其他字段可以具有任何字段类型。
允许的字段类型是:

  • signed int (AArch32 only).
  • unsigned int (AArch32 only).
  • signed long.
  • unsigned long.
  • signed long long.
  • unsigned long long.
  • pointer.
  • structure containing any of the types in this list.
  • union whose maximal-size member is any of the types in this list.

如果由 __attribute__((value_in_regs)) 限定的函数返回的结构类型违反上述任何规则,则编译器会生成相应的错误。如果要覆盖声明为 __attribute__((value_in_regs)) 的虚函数,则还必须将覆盖函数声明为 __attribute__((value_in_regs))。如果函数不匹配,编译器会产生错误。
声明为 __attribute__((value_in_regs)) 的函数与具有相同类型签名的普通函数不兼容函数指针。如果使用指向未声明为 __attribute__((value_in_regs)) 的函数的指针初始化指向声明为 __attribute__((value_in_regs)) 的函数的指针,则编译器会生成警告。
声明为 __attribute__((value_in_regs)) 的函数的返回类型必须在函数声明时已知。如果返回类型是不完整的类型,编译器会生成相应的错误。
示例

struct ReturnType
{
    long a;
    void *ptr;
    union U
    {
       char c;
       short s;
       int i;
       float f;
       double d;
       struct S1 {long long ll;} s1;
    } u;
};

extern __attribute__((value_in_regs)) struct retType g(long y);

3.21 __attribute__((visibility("visibility_type"))) 函数属性

此函数属性影响 ELF 符号的可见性。

语法

__attribute__((visibility("visibility_type")))

其中 visibility_type 是以下之一:

default

符号的假定可见性可以通过其他选项进行更改。默认可见性会覆盖此类更改。默认可见性对应于外部链接。

hidden

该符号未放入动态符号表中,因此没有其他可执行文件或共享库可以直接引用它。使用函数指针可以实现间接引用。

protected

该符号被放入动态符号表中,但定义模块中的引用绑定到本地符号。也就是说,该符号不能被另一个模块覆盖。

用法

除非指定default可见性,否则此属性旨在与否则将具有外部链接的声明一起使用。

您可以将此属性应用于 C 和 C++ 中的函数和变量。在 C++ 中,它还可以应用于类、结构、联合和枚举类型以及命名空间声明。

在命名空间声明的情况下,可见性属性适用于所有函数和变量定义。

示例

void __attribute__((visibility("protected"))) foo()
{
   ...
}

3.22 __attribute__((weak)) 函数属性

用__attribute__((weak)) 定义的函数弱导出它们的符号。
用 __attribute__((weak)) 声明的函数然后在没有 __attribute__((weak)) 的情况下定义的函数表现为弱函数。
示例

extern int Function_Attributes_weak_0 (int b) __attribute__((weak));

3.23 __attribute__((weakref("target"))) 函数属性

此函数属性将函数声明标记为别名,它本身不需要为目标符号提供函数定义。
语法

__attribute__((weakref("target")))

其中 target 是目标符号。
示例

在下面的示例中, foo() 通过弱引用调用 y():

extern void y(void);
static void x(void) __attribute__((weakref("y")));
void foo (void)
{
  ...
  x();
  ...
}

限制

此属性只能用于具有静态链接的函数。

3.24 类型属性

__attribute__ 关键字使您能够指定变量或结构字段、函数和类型的特殊属性。
关键字格式为以下之一:

__attribute__((attribute1, attribute2, ...))
__attribute__((__attribute1__, __attribute2__, ...))

例如:

typedef union { int i; float f; } U __attribute__((transparent_union));

可用的类型属性如下:

  • __attribute__((aligned))
  • __attribute__((packed))
  • __attribute__((transparent_union))

3.25 __attribute__((aligned)) 类型属性

对齐类型属性指定类型的最小对齐方式。

3.26 __attribute__((packed)) 类型属性

打包类型属性指定类型必须具有最小可能的对齐方式。此属性仅适用于结构和联合类型。
注意:

您必须直接从包含类型的变量访问结构或联合的打包成员。获取这样一个成员的地址会产生一个可能未对齐的普通指针。编译器假定指针是对齐的。即使目标支持未对齐的访问,取消引用这样的指针也可能是不安全的,因为某些指令总是需要字对齐的地址。
注意:

如果您获取压缩成员的地址,在大多数情况下,编译器会生成警告。
当您将 __attribute__((packed)) 指定给结构或联合时,它适用于结构或联合的所有成员。如果一个压缩结构有一个成员也是一个结构,那么这个成员结构有一个 1 字节的对齐。但是,packed 属性不适用于成员结构的成员。成员结构的成员继续保持自然对齐。
示例 3-2 示例

struct __attribute__((packed)) foobar 
{
  char x;
  short y;
}; 

short get_y(struct foobar *s) 
{
    // Correct usage: the compiler will not use unaligned accesses
    // unless they are allowed.
    return s->y;
} 

short get2_y(struct foobar *s) 
{
    short *p = &s->y; // Incorrect usage: 'p' might be an unaligned pointer.
    return *p;  // This might cause an unaligned access.
}

3.27 __attribute__((transparent_union)) 类型属性

transparent_union 类型属性使您能够指定transparent_union 类型。
当使用具有透明联合类型的参数定义函数时,使用联合中任何类型的参数调用该函数会导致联合对象的初始化,其成员具有传递参数的类型并且其值设置为传递的参数的值。
当联合数据类型由 __attribute__((transparent_union)) 限定时,透明联合适用于该类型的所有函数参数。
示例

typedef union { int i; float f; } U __attribute__((transparent_union));
void foo(U u)
{
    static int s;
    s += u.i;    /* Use the 'int' field */
}
void caller(void)
{
    foo(1);        /* u.i is set to 1 */
    foo(1.0f);     /* u.f is set to 1.0f */
}

3.28 变量属性

__attribute__ 关键字使您能够指定变量或结构字段、函数和类型的特殊属性。

关键字格式为以下之一:

__attribute__((attribute1, attribute2, ...))
__attribute__((__attribute1__, __attribute2__, ...))

例如:

可用的变量属性如下:

  • __attribute__((alias))
  • __attribute__((aligned))
  • __attribute__((deprecated))
  • __attribute__((packed))
  • __attribute__((section("name")))
  • __attribute__((unused))
  • __attribute__((used))
  • __attribute__((weak))
  • __attribute__((weakref("target")))

3.29 __attribute__((alias)) 变量属性

此变量属性使您可以为一个变量指定多个别名。
别名必须在与原始变量定义相同的翻译单元中声明。
注意:

不能在块范围内指定别名。编译器忽略附加到局部变量定义的别名属性,并将变量定义视为正常的局部定义。
在输出目标文件中,编译器将别名引用替换为对原始变量名的引用,并在原始名称旁边发出别名。例如:

int oldname = 1;
extern int newname __attribute__((alias("oldname")));

此代码编译为:

        .type   oldname,%object         @ @oldname
        .data
        .globl  oldname
        .align  2
oldname:
        .long   1                       @ 0x1
        .size   oldname, 4
        ...
        .globl  newname
newname = oldname

注意:

函数名称也可以使用相应的函数属性 __attribute__((alias)) 进行别名。

语法

type newname __attribute__((alias("oldname")));

其中:

oldname 是要别名的变量的名称

newname 是别名变量的新名称。

示例

#include <stdio.h>
int oldname = 1;
extern int newname __attribute__((alias("oldname"))); // declaration
void foo(void){
    printf("newname = %d\n", newname); // prints 1
}

3.30 __attribute__((aligned)) 变量属性

对齐变量属性指定变量或结构字段的最小对齐方式,以字节为单位。
示例

/* Aligns on 16-byte boundary */
int x __attribute__((aligned (16)));

/* In this case, the alignment used is the maximum alignment for a scalar data type. For ARM, this is 8 bytes. */
short my_array[3] __attribute__((aligned));

3.31 __attribute__((deprecated)) 变量属性

deprecated variable 属性允许声明已弃用的变量,而编译器不会发出任何警告或错误。但是,对已弃用变量的任何访问都会产生警告,但仍会编译。
警告给出了变量的使用位置和定义的位置。这可以帮助您确定不推荐使用特定定义的原因。
示例

extern int deprecated_var __attribute__((deprecated));
void foo()
{
    deprecated_var=1;
}

编译此示例会生成警告:

armclang --target=aarch64-arm-none-eabi -c test_deprecated.c
test_deprecated.c:4:3: warning: 'deprecated_var' is deprecated [-Wdeprecated-declarations]
  deprecated_var=1;
  ^
test_deprecated.c:1:12: note: 'deprecated_var' has been explicitly marked deprecated here
  extern int deprecated_var __attribute__((deprecated));
  ^
1 warning generated.

3.32 __attribute__((packed)) 变量属性

您可以在属于结构或联合成员的字段上指定打包变量属性。它指定成员字段具有最小可能的对齐方式。也就是说,一个字节用于变量字段,一个位用于位字段,除非您使用对齐属性指定更大的值。
示例

struct
{
    char a;
    int b __attribute__((packed));
} Variable_Attributes_packed_0;

注意:

您必须直接从结构或联合的变量访问结构或联合的压缩成员。获取这样一个成员的地址会产生一个可能未对齐的普通指针。编译器假定指针是对齐的。即使目标支持未对齐的访问,取消引用这样的指针也可能是不安全的,因为某些指令总是需要字对齐的地址。

注意:

如果您获取压缩成员的地址,在大多数情况下,编译器会生成警告。

3.33 __attribute__((section("name"))) 变量属性

section 属性指定变量必须放在特定的数据段中。通常,ARM® 编译器将其生成的数据放在 .data 和 .bss 等部分中。但是,您可能需要额外的数据部分,或者您可能希望变量出现在特殊部分中,例如,映射到特殊硬件。
如果使用 section 属性,只读变量放在 RO 数据段,可写变量放在 RW 数据段。
要将 ZI 数据放在命名节中,该节必须以前缀 .bss. 开头。非 ZI 数据不能放在名为 .bss 的节中。

示例

* in RO section */
const int descriptor[3] __attribute__((section ("descr"))) = { 1,2,3 };
/* in RW section */
long long rw_initialized[10] __attribute__((section ("INITIALIZED_RW"))) = {5};
/* in RW section */
long long rw[10] __attribute__((section ("RW")));
/* in ZI section */
int my_zi __attribute__((section (".bss.my_zi_section")));

注意:

部分名称必须是唯一的。您不能对不同的部分类型使用相同的部分名称。如果您对不同的节类型使用相同的节名,则编译器会将这些节合并为一个,并为该节提供首先分配给该节的函数或变量的类型。

3.34 __attribute__((used)) 变量属性

这个变量属性通知编译器一个静态变量将被保留在目标文件中,即使它没有被引用。
用 __attribute__((used)) 标记的数据在目标文件中被标记,以避免链接器将未使用的部分删除。
注意:

静态函数也可以通过使用 __attribute__((used)) 标记为已使用。
示例

static int lose_this = 1;
static int keep_this __attribute__((used)) = 2;     // retained in object file
static int keep_this_too __attribute__((used)) = 3; // retained in object file

3.35 __attribute__((unused)) 变量属性

如果变量被声明但从未被引用,编译器会发出警告。 __attribute__((unused)) 属性通知编译器期待一个未使用的变量,并告诉它不要发出警告。
注意:

默认情况下,编译器不会警告未使用的变量。使用 -Wunused-variable 专门启用此警告,或使用包含的 -W 值,例如 -Weverything。
__attribute__((unused)) 属性可用于警告大多数未使用的变量,但禁止对特定变量集发出警告。

示例

void foo()
{
    static int aStatic =0;
    int aUnused __attribute__((unused));
    int bUnused;
    aStatic++;
}

当使用合适的 -W 设置编译时,编译器会警告 bUnused 已声明但从未被引用,但不会警告 aUnused:

armclang --target=aarch64-arm-none-eabi -c test_unused.c -Wall
test_unused.c:5:7: warning: unused variable 'bUnused' [-Wunused-variable]
  int bUnused;
      ^
1 warning generated.

3.36 __attribute__((weak)) 变量属性

为变量生成弱符号,而不是默认符号。

extern int foo __attribute__((weak));

在链接时,强符号覆盖弱符号。此属性通过选择要链接的目标文件的特定组合,将弱符号替换为强符号。

3.37 __attribute__((weakref("target"))) 变量属性

此变量属性将变量声明标记为别名,它本身不需要为目标符号给出定义。

语法

__attribute__((weakref("target")))

其中 target 是目标符号。

示例

在以下示例中,通过弱引用为 a 分配了 y 的值:

extern int y;
static int x __attribute__((weakref("y")));
void foo (void)
{
  int a = x;
  ...
}

限制

此属性只能用于声明为静态的变量。

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值