c - 使用 uint64_t 的不便之处

标签 c performance embedded portability uint64

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

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

  1. 实际可移植性:是否所有微 Controller (包括 8 位 CPU)都能够处理 64 位整数?
  2. 性能:与 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/

相关文章:

c - 如何将迭代算法转换为递归求解

mysql - MongoDB vs MySQL 性能 - 简单查询

language-agnostic - 固件和嵌入式软件之间的真正区别是什么

c - 值0的套接字类型是什么类型?

c++ - x86 Intel Assembly 和 C++ - 数组周围的堆栈已损坏

比较 C 中从第 x 个字符开始的字符串 (C)

java - 日志记录框架注意事项

c# - Linq multiple order by 的性能更高吗?

c++ - 如何在VS2015中使用VisualGDB嵌入式C++重构特性

c - 显示 MSP 430 错误值