因此,对于其原因typedef:ED原始数据类型是抽象低级别表示,并使其更容易理解(uint64_t而不是long long类型,这是8个字节).
但是,有uint_fast32_t与之相同typedef的uint32_t.使用"快速"版本会使程序更快吗?
这个问题的动机是我在C/C++中实现加密算法(例如SHA-1),编写可移植平台无关的代码,并彻底避免未定义的行为.
假设标准化的加密算法要求您实现此目的:
b = (a << 31) & 0xFFFFFFFF
Run Code Online (Sandbox Code Playgroud)
where a和b是无符号的32位整数.请注意,在结果中,我们丢弃高于最低32位的任何位.
作为第一个天真的近似,我们可以假设int在大多数平台上都是32位宽,所以我们写:
unsigned int a = (...);
unsigned int b = a << 31;
Run Code Online (Sandbox Code Playgroud)
我们知道这个代码无处不在,因为int在某些系统上是16位宽,在其他系统上是64位,甚至可能是36位.但是使用stdint.h,我们可以使用以下uint32_t类型改进此代码:
uint32_t a = (...);
uint32_t b = a << 31;
Run Code Online (Sandbox Code Playgroud)
所以我们完成了,对吧?这就是我多年来的想法.... 不完全的.假设在某个平台上,我们有:
// stdint.h
typedef unsigned short uint32_t;
Run Code Online (Sandbox Code Playgroud)
在C/C++中执行算术运算的规则是,如果类型(例如short)比类型更窄int,那么int如果所有值都适合,则它会变宽,unsigned int否则.
假设编译器定义short为32位(带符号)和int48位(带符号).然后这些代码行:
uint32_t a = (...);
uint32_t b = a << …Run Code Online (Sandbox Code Playgroud) 在汇编编程中,想要从寄存器的低位计算某些东西是相当普遍的,这些位不能保证将其他位置零.在像C这样的高级语言中,你只需将输入转换为小尺寸,让编译器决定是否需要分别将每个输入的高位归零,或者是否可以在输出之后切断结果的高位.事实.
这是为x86-64的(又名AMD64),出于各种原因尤其常见1,其中的一些是存在于其它的ISA.
我将使用64位x86作为示例,但目的是询问/讨论2的补码和无符号二进制算法,因为所有现代CPU都使用它.(注意,C和C++不保证两个补码4,并且有符号溢出是未定义的行为.)
作为示例,考虑一个可以编译为LEA指令2的简单函数.(在X86-64 SysV的(Linux)的ABI 3,前两个函数参数是rdi和rsi,与在返回rax. int是一个32位的类型.)
; int intfunc(int a, int b) { return a + b*4 + 3; }
intfunc:
lea eax, [edi + esi*4 + 3] ; the obvious choice, but gcc can do better
ret
Run Code Online (Sandbox Code Playgroud)
gcc知道即使是负有符号整数,加法也只是从右到左,所以输入的高位不会影响进入的内容eax.因此,它保存了一个指令字节并使用 lea eax, [rdi + rsi*4 + 3]
为什么它有效?
1为什么x86-64频繁出现这种情况:x86-64有可变长度指令,其中额外的前缀字节改变了操作数大小(从32到64或16),因此在指令中通常可以保存一个字节.以相同的速度执行.当写入低8b或16b的寄存器(或稍后读取完整寄存器(Intel pre-IvB)时的失速)时,它也具有错误依赖性(AMD/P4/Silvermont):由于历史原因, …