比一个整数上的位移(对于AMD64或x86架构)更快(比需要更少的CPU周期)更快(比至少1个位置)?我怀疑答案是肯定的,因为在这两种情况下都会使用相同的32位或64位CPU指令,两者都需要相同的时钟周期。这是真的吗?
答案 0 :(得分:2)
这取决于。一般来说,如果你有一个N位处理器,那么很可能任何高达N位的东西都需要相同的时间来移位,较大的变量需要更长的时间。如果您正在对字节进行操作,但希望确保使用适当大小的整数来表示速度,则使用类型uint_fast8_t
。
但是:如果你在循环中进行位移,那么编译器可能能够对代码进行矢量化。如果您的处理器具有SSE2指令,则它可以在一条指令中执行8次16位移位。如果你有AVX甚至AVX512,那么它可以在一条指令中进行16位甚至32位16位移位。但是,这是否比使用常规指令更有效取决于将许多变量加载到SSE寄存器中的容易程度,以及如果您执行的操作多于对它们进行位移的操作。
查看编译器的汇编器输出是有益的(例如,使用gcc -save-temps
编译程序并查看生成的.s
文件。请注意,所选的优化级别对生成的汇编程序有很大的影响。
确定最快变量大小的最佳方法就是测量它。
答案 1 :(得分:2)
我的假设是8位或16位(无符号)整数的移位与32位字机器上32位量的位移相同。
大多数32位字长处理器在内部以32位数量运行。桶形移位器,算术单元等设计用于32位操作。数据获取机制将在移位操作发生之前将8位或16位数量转换为32位数量。 32位数量不需要任何调整,因此较小的整数可能会有轻微的延迟。
另一方面,可能存在具有特殊数据路径的处理器,用于8位或16位大小的整数。
验证的方法是在您的系统和其他目标系统上进行配置。
另外,问问自己执行时间差异是重要还是重要。
答案 2 :(得分:1)
我之前发布的代码不正确。虽然代码包含一个移位,但由于结果未存储,编译器只是跳过它。这是一个简单的int示例:
void main() {
int value = 0;
value = value << 3;
}
简短的例子:
void foo() {
short value = 0;
value = value << 3;
}
整数示例生成:
.file "main.c"
.text
.globl _Z3foov
.def _Z3foov; .scl 2; .type 32; .endef
.seh_proc _Z3foov
_Z3foov:
.LFB0:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $16, %rsp
.seh_stackalloc 16
.seh_endprologue
movl $0, -4(%rbp)
sall $3, -4(%rbp)
nop
addq $16, %rsp
popq %rbp
ret
.seh_endproc
.ident "GCC: (GNU) 5.4.0"
简短示例生成:
.file "main.c"
.text
.globl _Z3foov
.def _Z3foov; .scl 2; .type 32; .endef
.seh_proc _Z3foov
_Z3foov:
.LFB0:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $16, %rsp
.seh_stackalloc 16
.seh_endprologue
movw $0, -2(%rbp)
movswl -2(%rbp), %eax
sall $3, %eax
movw %ax, -2(%rbp)
nop
addq $16, %rsp
popq %rbp
ret
.seh_endproc
.ident "GCC: (GNU) 5.4.0"
简短的例子执行:
movw $0, -2(%rbp)
movswl -2(%rbp), %eax
sall $3, %eax
movw %ax, -2(%rbp)
整数示例执行:
movl $0, -4(%rbp)
sall $3, -4(%rbp)
所以看起来没有任何编译器优化,整数移位实际上更快。