【发布时间】:2020-07-07 09:25:33
【问题描述】:
当试图创建一个编译时哈希宏时,它可以工作,但它有问题。所以我想如果字符串在编译时是已知的(它们是),整个散列应该被优化为一个常数。 此 gcc C99 代码启用了优化级别 -O3:
#include <stdio.h>
int main(void)
{
char const *const string = "hello";
int hash = 0;
for (unsigned char i=0; i < sizeof string; ++i)
{
hash += string[i]; //reeaally simple hash :)
}
printf("%i", hash);
return 0;
}
生成以下汇编代码:
.LC0:
.string "hello"
.LC1:
.string "%i"
main:
sub rsp, 8
movsx eax, BYTE PTR .LC0[rip+6]
movsx edx, BYTE PTR .LC0[rip+7]
mov edi, OFFSET FLAT:.LC1
lea esi, [rax+532+rdx]
xor eax, eax
call printf
xor eax, eax
add rsp, 8
ret
虽然相同代码,我只是将“hello”更改为“hello w”,生成了这个汇编代码,它完全优化了散列:
.LC0:
.string "%i"
main:
sub rsp, 8
mov esi, 683
mov edi, OFFSET FLAT:.LC0
xor eax, eax
call printf
xor eax, eax
add rsp, 8
ret
是什么原因?这是否意味着我不能使用这种散列方式,因为开销可能不会得到优化?我怎样才能确保不会有任何开销,有什么替代方案?
编辑 1: 我玩了一下,似乎如果字符串中的字符数是 6,如果字符数是 7,它就不会被优化掉,它会
【问题讨论】:
-
是的,这很奇怪。我的意思是……它们都应该被优化,因为这里的一切都是不变的。
-
用叮当它工作。问题是这个散列宏是库的一部分。这意味着如果您没有 clang 并包含该库,那么您的整个程序可能会比我奶奶运行得慢
-
尝试以下字符串:“1234”、“12345”和“123456”。你会看到你得到三个不同的结果。优化器正在工作,它根据字符串的长度选择不同的策略。
-
我有点认为这是展开循环的一些硬编码限制,但它似乎与
sizeof有关。如果将其设为 20 个字符的字符串并将循环条件硬编码为i < 20,它仍然是优化的。编辑:或者...更好的是,如果您包含string.h并使用strlen,您也会保持优化。 -
如果你使用了
unsigned char,你的编译器理论上可以使用psadbw优化它,以获得8或16字节字符串块的水平总和。 (实际上它仍然是有符号字节的胜利,但需要进行一些预处理。)
标签: c string assembly optimization