使用uint64_t的不便

mad*_*phy 5 c embedded performance portability uint64

我有一个高度可移植的库(即使没有内核,它也可以在任何地方编译和运行良好),我希望它尽可能保持可移植性。到目前为止,我已经避免使用 64 位数据类型,但我现在可能需要使用它们 \xe2\x80\x93 准确地说,我需要一个 64 位位掩码。

\n

uint64_t我从来没有真正考虑过它,而且我也不是一个足够的硬件专家(特别是在嵌入式系统方面),但我现在想知道:使用(或等效地)有什么不便uint_least64_t?我可以想到两种方法来解决我的问题:

\n
    \n
  1. 实际可移植性:所有微控制器\xe2\x80\x93(包括8位CPU\xe2\x80\x93)都能够处理64位整数吗?
  2. \n
  3. 性能:与 32 位整数相比,8 位 CPU 对 64 位整数执行按位运算的速度有多慢?我正在设计的函数只有一个 64 位变量,但会对其执行大量按位操作(即在循环中)。
  4. \n
\n

Lun*_*din 2

对符合标准的 C 编译器有各种最低要求。C 语言允许两种形式的编译器:托管编译器独立编译器。托管意味着在操作系统之上运行,而独立运行则无需操作系统。大多数嵌入式系统编译器都是独立的实现。

独立编译器有一些余地,它们不需要支持所有标准库,但需要支持其中的最小子集。这包括stdint.h(参见 C17 4/6)。这又要求编译器实现以下内容(C17 7.20.1.2/3):

需要以下类型:

int_least8_t int_least16_t int_least32_t int_least64_t uint_least8_t
uint_least16_t uint_least32_t uint_least64_t

因此,微控制器编译器不需要支持 uint64_t,但它必须(奇怪的是)支持uint_least64_t。实际上,这意味着编译器也可能添加uint64_t支持,因为在这种情况下是相同的。

至于8位MCU支持什么...它通过指令集支持8位算术,在某些特殊情况下还支持使用索引寄存器的一些16位运算。但一般来说,只要使用大于 8 位的类型,就必须依赖软件库。

因此,如果您尝试在 8 位机器上进行 32 位算术,它会将一些编译器软件库内联到代码中,结果将是数百条汇编指令,使此类代码非常低效且消耗内存。64 位会更糟。

与缺少 FPU 的 MCU 上的浮点数一样,这些也会通过软件浮点库生成极其低效的代码。


为了说明这一点,请看一下这段未优化的代码,在 8 位 AVR (gcc) 上进行一些非常简单的 64 位添加:https://godbolt.org/z/ezbKjY
它实际上支持uint64_t,但编译器吐出了巨大的大量的开销代码,大约 100 条指令。在它的中间,调用call __adddi3隐藏在可执行文件中的内部编译器函数。

如果我们启用优化,我们会得到

add64:
        push r10
        push r11
        push r12
        push r13
        push r14
        push r15
        push r16
        push r17
        call __adddi3
        pop r17
        pop r16
        pop r15
        pop r14
        pop r13
        pop r12
        pop r11
        pop r10
        ret
Run Code Online (Sandbox Code Playgroud)

我们必须挖掘库源代码或实时单步执行程序集以查看内部有多少代码__adddi3。我想这仍然不是一个微不足道的功能。

因此,正如您希望知道的那样,在 8 位 CPU 上执行 64 位算术是一个非常糟糕的主意。