ARM 编译器 armclang 参考指南 - 特定于编译器特定的关键字和运算符

本文详细介绍了ARM编译器armclang针对C和C++标准的扩展,包括__alignof__、__asm、__declspec及其相关属性如__noinline__、__noreturn__、__nothrow__等。__alignof__用于查询类型或变量的对齐方式,__asm则用于内联汇编和嵌入式汇编,而__declspec则提供函数和对象的特殊属性设定,如控制内联、异常处理等。
摘要由CSDN通过智能技术生成

第 2 章 特定于编译器的关键字和运算符

总结了特定于编译器的关键字和运算符,它们是 C 和 C++ 标准的扩展。
它包含以下部分:

2.1 编译器特定的关键字和运算符.
2.2 __alignof__.
2.3 __asm.
2.4 __declspec attributes.
2.5 __declspec(noinline).
2.6 __declspec(noreturn).
2.7 __declspec(nothrow).
2.8 __inline.

2.1 编译器特定的关键字和运算符.

ARM® 编译器 armclang 提供了对 C 和 C++ 标准进行扩展的关键字。
不记录没有特定于 ARM 编译器的行为或限制的标准 C 和标准 C++ 关键字。
ARM 编译器支持的关键字扩展:

  • __alignof__
  • __asm
  • __declspec
  • __inline

2.2 __alignof__

__alignof__ 关键字使您能够查询类型或变量的对齐方式。
注意:

此关键字是 ARM® 编译器支持的 GNU 编译器扩展。
语法

__alignof__(type)

__alignof__(expr)

其中:

type 是一个类型

expr 是一个左值。
返回值

__alignof__(type) 返回类型的对齐要求,如果没有对齐要求,则返回 1。
__alignof__(expr) 返回左值 expr 类型的对齐要求,如果没有对齐要求,则返回 1。
示例

下面的示例显示了各种数据类型的对齐要求,首先直接来自数据类型,然后来自相应数据类型的左值:

#include <stdio.h>

int main(void)
{
  int       var_i;
  char      var_c;
  double    var_d;
  float     var_f;
  long      var_l;
  long long var_ll;

  printf("Alignment requirement from data type:\n");
  printf("  int       : %d\n", __alignof__(int));
  printf("  char      : %d\n", __alignof__(char));
  printf("  double    : %d\n", __alignof__(double));
  printf("  float     : %d\n", __alignof__(float));
  printf("  long      : %d\n", __alignof__(long));
  printf("  long long : %d\n", __alignof__(long long));
  printf("\n");
  printf("Alignment requirement from data type of lvalue:\n");
  printf("  int       : %d\n", __alignof__(var_i));
  printf("  char      : %d\n", __alignof__(var_c));
  printf("  double    : %d\n", __alignof__(var_d));
  printf("  float     : %d\n", __alignof__(var_f));
  printf("  long      : %d\n", __alignof__(var_l));
  printf("  long long : %d\n", __alignof__(var_ll));
}

使用以下命令编译会产生以下输出:

armclang --target=arm-arm-none-eabi -march=armv8-a alignof_test.c -o alignof.axf
Alignment requirement from data type:
  int       : 4
  char      : 1
  double    : 8
  float     : 4
  long      : 4
  long long : 8

Alignment requirement from data type of lvalue:
  int       : 4
  char      : 1
  double    : 8
  float     : 4
  long      : 4
  long long : 8

2.3 __asm

这个关键字将信息传递给 armclang 汇编器。
此关键字的确切作用取决于其用法。
用法

内联汇编

__asm 关键字可以将内联 GCC 语法汇编代码合并到一个函数中。例如:

#include <stdio.h>

int add(int i, int j)
{
  int res = 0;
  __asm (
    "ADD %[result], %[input_i], %[input_j]"
    : [result] "=r" (res)
    : [input_i] "r" (i), [input_j] "r" (j)
  );
  return res;
}

int main(void)
{
  int a = 1;
  int b = 2;
  int c = 0;

  c = add(a,b);

  printf("Result of %d + %d = %d\n", a, b, c);
}

__asm 内联汇编语句的一般形式是:

__asm(code [: output_operand_list [: input_operand_list [: clobbered_register_list]]]);

code 是汇编代码。在我们的示例中,这是“ADD %[result], %[input_i], %[input_j]”。
output_operand_list 是可选的输出操作数列表,以逗号分隔。每个操作数由方括号中的符号名称、约束字符串和括号中的 C 表达式组成。在我们的示例中,有一个输出操作数:[result] "=r" (res)。
input_operand_list 是输入操作数的可选列表,以逗号分隔。输入操作数使用与输出操作数相同的语法。在我们的示例中,有两个输入操作数:[input_i] "r" (i),[input_j] "r" (j)。
clobbered_register_list 是一个可选的被破坏寄存器列表。在我们的示例中,这被省略了。

嵌入式汇编

对于嵌入式汇编,您不能在函数声明中使用 __asm 关键字。在函数声明中使用 __attribute__((naked)) 函数属性。有关详细信息,请参阅 __attribute__((naked))。例如:

__attribute__((naked)) void foo (int i);

具有 __attribute__((naked)) 函数属性的裸函数仅支持基本格式的汇编指令:

__asm(code);

汇编标签

__asm 关键字可以为 C 符号指定程序集标签。例如:

int count __asm__("count_v1"); // export count_v1, not count

2.4 __declspec 属性

__declspec 关键字使您能够指定对象和函数的特殊属性。
__declspec 关键字必须作为声明规范的前缀。例如:

__declspec(noreturn) void overflow(void);

可用的 __declspec 属性如下:

  • __declspec(noinline)
  • __declspec(noreturn)
  • __declspec(nothrow)

__declspec 属性是存储类修饰符。它们不影响函数或变量的类型。

2.5 __declspec(noinline)

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

此 __declspec 属性具有等效的函数属性 __attribute__((noinline))。
示例

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

2.6 __declspec(noreturn)

__declspec(noreturn) 属性断言函数永远不会返回。
注意:

此 __declspec 属性具有等效的函数属性 __attribute__((noreturn))。
用法

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

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

__declspec(noreturn) void overflow(void); // never return on overflow
int negate(int x) 
{
    if (x == 0x80000000) overflow();
    return -x;
}

2.7 __declspec(nothrow)

__declspec(nothrow) 属性断言对函数的调用永远不会导致 C++ 异常从被调用者传播到调用者。
ARM 库头文件会自动将此限定符添加到 C 函数的声明中,根据 ISO C 标准,这些函数永远不会引发异常。但是,为 C 库函数生成的展开表存在一些限制,这些函数可能会在 C++ 上下文中引发异常,例如 bsearch 和 qsort。
注意:

此 __declspec 属性具有等效的函数属性 __attribute__((nothrow))。
用法

如果编译器知道一个函数永远不会抛出异常,它可能会为该函数的调用者生成更小的异常处理表。
限制

如果对函数的调用导致 C++ 异常从被调用者传播到调用者,则行为未定义。
当未启用异常进行编译时,此修饰符将被忽略。
示例

struct S
{
    ~S();
};
__declspec(nothrow) extern void f(void);
void g(void)
{
    S s;
    f();
}

2.8 __inline

__inline 关键字向编译器建议它内联编译 C 或 C++ 函数,如果这样做是明智的。
__inline 可以在 C90 代码中使用,并作为 C99 内联关键字的替代品。
armclang 支持 __inline 和 __inline__。
示例

static __inline int f(int x){
    return x*5+1;
}

int g(int x, int y){
    return f(x) + f(y);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值