我有一个高度可移植的库(即使没有内核,它也能在任何地方编译和运行良好),我希望它尽可能保持可移植性。到目前为止,我已经避免使用 64 位数据类型,但我现在可能需要使用它们——准确地说,我需要一个 64 位位掩码。
我从来没有真正考虑过它,我也不是一个足够的硬件专家(尤其是在嵌入式系统方面),但我现在想知道:使用 uint64_t
有什么不便之处(或者,等价地, uint_least64_t
)?我可以想到两种方法来解决我的问题:
- 实际可移植性:是否所有微 Controller (包括 8 位 CPU)都能够处理 64 位整数?
- 性能:与 32 位整数相比,8 位 CPU 对 64 位整数执行按位运算的速度有多慢?我正在设计的函数只有一个 64 位变量,但会对其执行很多位运算(即在循环中)。
最佳答案
对符合标准的 C 编译器有各种最低要求。 C 语言允许两种形式的编译器:托管 和独立。托管意味着在操作系统之上运行,而独立运行则没有操作系统。大多数嵌入式系统编译器都是独立的实现。
独立编译器有一些余地,它们不需要支持所有的标准库,但它们需要支持它们的最小子集。这包括 stdint.h
(参见 C17 4/6)。这反过来又要求编译器实现以下 (C17 7.20.1.2/3):
The following types are required:
int_least8_t int_least16_t int_least32_t int_least64_t
uint_least8_t uint_least16_t uint_least32_t uint_least64_t
所以微 Controller 编译器不需要支持uint64_t
,但它必须(奇怪的是)支持uint_least64_t
。实际上,这意味着编译器也可以添加 uint64_t
支持,因为在这种情况下是一样的。
至于 8 位 MCU 支持什么...它通过指令集支持 8 位运算,在某些特殊情况下还支持一些使用变址寄存器的 16 位运算。但一般来说,只要使用大于 8 位的类型,它就必须依赖软件库。
因此,如果您尝试在 8 bit 上进行 32 位运算,它会将一些编译器软件库与代码内联,结果将是数百条汇编指令,从而使此类代码非常低效且耗费内存。 64 位会更糟。
对于缺少 FPU 的 MCU 上的 float 也是如此,这些也会通过软件浮点库生成极其低效的代码。
为了说明这一点,请看一下这个未优化的代码,用于在 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
我们必须深入研究库源代码或实时单步执行程序集,以查看 __adddi3
中有多少代码。我想这仍然不是一个微不足道的函数。
因此,正如您希望知道的那样,在 8 位 CPU 上执行 64 位算术是一个非常糟糕的主意。
关于c - 使用 uint64_t 的不便之处,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64702944/