C 使用uint64\t的不便之处
我有一个高度可移植的库(它在任何地方都可以编译并运行良好,即使没有内核),我希望它尽可能保持可移植性。到目前为止,我已经避免使用64位数据类型,但我现在可能需要使用它们——确切地说,我需要一个64位位掩码 我从来没有真正考虑过这一点,而且我还不够精通硬件(特别是在嵌入式系统方面),但我现在想知道:使用C 使用uint64\t的不便之处,c,performance,embedded,portability,uint64,C,Performance,Embedded,Portability,Uint64,我有一个高度可移植的库(它在任何地方都可以编译并运行良好,即使没有内核),我希望它尽可能保持可移植性。到目前为止,我已经避免使用64位数据类型,但我现在可能需要使用它们——确切地说,我需要一个64位位掩码 我从来没有真正考虑过这一点,而且我还不够精通硬件(特别是在嵌入式系统方面),但我现在想知道:使用uint64\u t(或者,等效地说,uint\u t)有什么不便之处?我可以想出两种方法来回答我的问题: 实际可移植性:所有微控制器——包括8位CPU——都能处理64位整数吗 性能:与32位整数相
uint64\u t
(或者,等效地说,uint\u t
)有什么不便之处?我可以想出两种方法来回答我的问题:
对合格的C编译器有各种最低要求。C语言允许两种形式的编译器:托管编译器和独立编译器。Hosted是指在操作系统上运行,而独立运行则不需要操作系统。大多数嵌入式系统编译器都是独立的实现 独立编译器有一定的回旋余地,它们不需要支持所有标准库,但需要支持它们的最小子集。这包括
stdint.h
(参见C17 4/6)。这反过来要求编译器实现以下内容(C17.20.1.2/3):
以下类型是必需的:
至少8分钟
至少16分钟
至少32分钟
至少内部64\u t至少8 至少16分钟 至少32分钟 至少有64个 因此,微控制器编译器不需要支持
uint64\u t
,但它必须(奇怪的是)支持uint64\u t
。实际上,这意味着编译器也可以添加uint64\t
支持,因为在本例中也是这样
至于8位MCU支持什么。。。它通过指令集支持8位算术运算,在某些特殊情况下还支持使用索引寄存器的一些16位运算。但一般来说,只要使用大于8位的类型,它就必须依赖软件库
因此,如果您在8位处理器上尝试32位算术,它会将一些编译器软件库与代码内联,结果将是数百条汇编指令,这使得此类代码非常低效且占用内存。64位将更糟糕
对于缺少FPU的MCU上的浮点数,同样的事情也会通过软件浮点数库生成效率极低的代码
为了说明这一点,我们来看一下8-AVR(gcc)上一些非常简单的64位加法的非优化代码:
它实际上支持
uint64\u t
,但编译器输出了大量开销代码,大约100条指令。在中间,调用一个内部编译器函数<代码>调用*AddiD3隐藏在可执行文件中。
如果我们启用优化,我们将得到
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
我们必须通过挖掘库源代码或程序集的单步运行来查看\uuu adddi3
中有多少代码。我想这仍然不是一个简单的函数
正如你所希望的,在一个8位CPU上做64位运算是一个很坏的想法。
嗯,如果你的首要关注点是保持一个公平的兼容性级别,这就是避免使用64位数字的原因,为什么不使用一个数组< <代码> int >代码>整数,并考虑使用一个完整的整数来存储,比如说,30位 我建议您查看有关使用位掩码(大于32位)表示(例如,select(2)
系统调用接触的文件)的标准库源,以及如何使用FDSET
宏
正确的情况是,您可能有一个问题,即决定是否在用于表示位图的数据类型中超过32位的限制,或者(暂时)使用仍然可用的64位类型来解决问题。这将是下一个规模的问题,当你得到大约64位位的位掩码,你将最终不得不越过这条线
作为练习,您现在就可以这样做,您将了解到最后的数据类型或多或少是一组较大的位,您可以根据需要使用它们。您是否计划使用80位长双精度值来存储大于64位的位掩码?我想你不会的,所以想想阵列解决方案,它可能会永远解决你的问题
如果你的问题是我的情况,我会写一个32位无符号数的数组,这样所有的位在移位、位运算等方面都表现相同
#define FDSET_TYPE(name, N) unsigned int name[((N) + 31U) >> 5]
#define FDSET_ISSET(name, N) ((name[(N) >> 5] & 1 << (N & 0x1f)) != 0)
...
FDSET_TYPE(name, 126);
...
if (FDSET_ISSET(name, 35)) { ...
#定义FDSET_类型(名称,N)无符号整数名称[((N)+31U)>>5]
#定义FDSET_ISSET(名称,N)((名称[(N)>>5]&1 8位CPU始终能够处理多字节算术和位操作,但效率不是很高。64位的执行时间通常是32位的两倍,但如下所述,可以免费检查或设置/清除内存中的单个位。即使8位CPU也可以处理64位值。按位操作通常是优化良好。在8位CPU上,检查单个标志通常与检查2 32位或4 16位值上的单个标志一样快。我使用标准的64位类型,让编译器计算出来。这是一样的。只需为所有需要的操作定义一组宏/函数(setbit、getbit、clearbit,可能是mask)并使用这些。一旦你意识到你实际上需要超过64位,或者你的机器不提供64位,这将有助于你。@madmurphy将位掩码拆分为2,如果你能形成比编译器更好的代码。否则,请相信你的编译器和代码的清晰性。使用比这更高级别的代码可以节省你的宝贵时间好的,回答得很好。不过,请注意