为什么要将XOR与文字而不是反转(非位)使用
Why use xor with a literal instead of inversion (bitwise not)
我遇到了此CRC32代码,很好奇为什么作者选择使用
crc = crc ^ ~0U;
而不是
crc = ~crc;
据我所知,它们是等效的。
我什至在Visual Studio 2010中拆除了两个版本。
未优化构建:
crc = crc ^ ~0U;
009D13F4 mov eax,dword ptr [crc]
009D13F7 xor eax,0FFFFFFFFh
009D13FA mov dword ptr [crc],eax
crc = ~crc;
011C13F4 mov eax,dword ptr [crc]
011C13F7 not eax
011C13F9 mov dword ptr [crc],eax
我也无法通过思考每个指令所需的周期数来证明代码合理,因为两者都应该花1个周期来完成。实际上, xor 可能不得不从某个地方加载字面的罚款,尽管我不确定这一点。
所以我认为这可能只是描述算法的首选方法,而不是一种优化...这是正确的吗?
编辑1:
,由于我只是意识到crc
变量的类型可能很重要,要提及我包括整个代码(少量查找表,太大了),因此您不必遵循链接。
uint32_t crc32(uint32_t crc, const void *buf, size_t size)
{
const uint8_t *p;
p = buf;
crc = crc ^ ~0U;
while (size--)
{
crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
}
return crc ^ ~0U;
}
编辑2:
有人提出了一个优化的构建的事实,所以我已经制作了一个,并将其包括在下面。
优化构建:
请注意,整个函数(包括下面的最后一个编辑中)已列为。
// crc = crc ^ ~0U;
zeroCrc = 0;
zeroCrc = crc32(zeroCrc, zeroBufferSmall, sizeof(zeroBufferSmall));
00971148 mov ecx,14h
0097114D lea edx,[ebp-40h]
00971150 or eax,0FFFFFFFFh
00971153 movzx esi,byte ptr [edx]
00971156 xor esi,eax
00971158 and esi,0FFh
0097115E shr eax,8
00971161 xor eax,dword ptr ___defaultmatherr+4 (973018h)[esi*4]
00971168 add edx,ebx
0097116A sub ecx,ebx
0097116C jne main+153h (971153h)
0097116E not eax
00971170 mov ebx,eax
// crc = ~crc;
zeroCrc = 0;
zeroCrc = crc32(zeroCrc, zeroBufferSmall, sizeof(zeroBufferSmall));
01251148 mov ecx,14h
0125114D lea edx,[ebp-40h]
01251150 or eax,0FFFFFFFFh
01251153 movzx esi,byte ptr [edx]
01251156 xor esi,eax
01251158 and esi,0FFh
0125115E shr eax,8
01251161 xor eax,dword ptr ___defaultmatherr+4 (1253018h)[esi*4]
01251168 add edx,ebx
0125116A sub ecx,ebx
0125116C jne main+153h (1251153h)
0125116E not eax
01251170 mov ebx,eax
尚未提到的东西;如果此代码在具有16位unsigned int
的计算机上编译,则这两个代码段为不同的。
crc
被指定为32位的无符号积分类型。~crc
将倒转所有位,但是如果unsigned int
为16位,则crc = crc ^ ~0U
只会倒转16位。
我对CRC算法不太了解这是故意还是错误,也许Hivert可以澄清。尽管查看OP发布的示例代码,但确实确实会改变随后的循环。
nb。很抱歉将其发布为"答案",因为它不是答案,但是它太大了,无法适应评论:)
简短的答案是:因为它允许所有CRC的
具有统一算法原因是:CRC有很多变体。每个都取决于用于欧几里得分裂的Z/Z2多项式。通常是使用Aram Perez在本文中描述的算法实现的。现在,根据您使用的多项式,在算法末尾有一个最终的XOR,该XOR取决于多项式的目标是消除某些角度的情况。碰巧的是,对于CRC32,这与全局相同,但对于所有CRC而言,这并非如此。 考虑一条消息,该消息以一些零位开始。直到消息中的第一个转移到消息中,其余的都不包含零以外的任何东西。这是一种危险的情况,因为以一个或多个零开头的数据包可能完全合法,并且CRC不会注意到零或添加的零。要合法!)消除这种弱点的简单方法是从剩余的剩余时间开始。称为初始剩余的参数告诉您针对特定CRC标准的值。crcslow()和crcfast()函数只需要一个小更改: crc剩余= initial_remainder; 出于类似原因而存在最终的XOR值。要实现此功能,只需更改CRCSLOW()和CRCFAST()返回的值,如下所示: 返回(剩余 ^ final_xor_value); 如果最终的XOR值由所有XOR值组成(如CRC-32标准中所示),那么此额外的步骤将与补充最终剩余成员具有相同的效果。方式允许在您的特定应用中使用任何可能的值。
只是为了将我自己的猜测添加到混音中, x ^ 0x0001
保留了最后一块,并将其flipp flipp flipp;关闭最后一位使用x & 0xFFFE
或x & ~0x0001
;要打开最后一个位无条件使用x | 0x0001
。即,如果您要做很多扭曲,您的手指可能知道这些习语,只是在不经过思考的情况下将它们推出。
我怀疑有任何深刻的原因。也许这就是作者对此的思考("我只用所有的人"),或者也许是在算法定义中表达的方式。
我认为这是出于同样的原因
const int zero = 0;
和其他写作
const int zero = 0x00000000;
不同的人认为不同的方式。即使是基本操作。
- 如何确定我已使用非编码文件到达 EOF?
- 如何在C++中使用非静态成员函数作为回调函数
- 如何使用非默认构造函数实例化模板化类
- 如何使用非类型模板参数传入指向数组的指针
- 在C++中使用非常量引用作为常量
- 有没有一种代码密度较低的方法来使用非默认构造函数初始化数组?
- c++ 在非类函数中使用类变量
- 使用英特尔内联函数将打包的 8 位整数乘以浮点数向量
- 使用 VS2015 在 Windows 10 上构建 Fortran .lib x64 位并将其链接到 C++
- 是否可以使用基类非虚拟方法中的派生类虚拟方法?
- c++ 获取非语法使用"&"创建指针
- Windows API "CreateWindowEx" 在 Python (3.6.8) 64 位使用的 DLL 中工作吗?
- 保证非 odr 使用的全局变量的延迟动态初始化
- 大括号初始化可防止非常量使用临时
- 为什么要将XOR与文字而不是反转(非位)使用
- 使用非 32 位整数是否合理
- 正在创建非odr使用的文字类型
- 有没有办法"reset" getopt用于非全局使用?
- 对非对象使用成员初始值设定项列表不好吗
- c++ opencv编译错误- Windows7 64位使用Eclipse CDT