仅当它为 0 时如何启用 octed 中的位?
How to enable a bit in octed only if it's 0?
比如我有以下号码:
0x FF 00 FF
现在,我希望 00 部分只有在它为 0 时才为 1。我需要检查每个字节还是有可以在这里使用的位技巧?
示例:
我有一个无符号长 IP,我用字符串函数对其进行哈希处理,但该函数终止于空字节,因此我需要将所有空字节设置为 1:
0x7F000001(127.0.0.1,可以是 0x0100007F,但取决于平台)
现在,我想将 0 字节变成 1:
0x7F010101(所以会变成127.1.1.1)
这是做我想做的唯一方法,这
char ip_sz[5];
*(unsigned long*)ip_sz = ulong_ip;
if (!ip_sz[0]) ip_sz[0] = 1;
if (!ip_sz[1]) ip_sz[1] = 1;
if (!ip_sz[2]) ip_sz[2] = 1;
if (!ip_sz[3]) ip_sz[3] = 1;
?
真的,好奇。我不关心性能,因为我知道编译器无论如何都会优化它。
您可以通过应用 位掩码 来检查整个字节是否为零(即在您希望检查的位置包含 1 而在所有其他位置包含零的数字*) 到它。
在你的情况下,你需要一个位掩码,在从零开始的位置 7 到 15(含)中有八个连续的 1,即 0x00FF00
。如果按位 "AND" &
应用于掩码和数字 n
,仅当位置 7 到 15 中 n
的所有位均为零时,结果才为零。否则,结果将是一些非零数。
int n = 0xFF00FF;
int mask = 0x00FF00;
if ((n & mask) == 0) {
... // Modify n as needed
}
您可以手动构造一个八位位掩码,或者使用左移运算符,如下所示:
(0xFF) // 0x000000FF
(0xFF << 8) // 0x0000FF00
(0xFF << 16) // 0x00FF0000
(0xFF << 24) // 0xFF000000
so, I would still have to do four if
's?
在这种特定情况下,if
不是必需的,因为 C 中的一个小技巧:您可以使用 !
将零转换为一,将任何其他数字转换为零。我将用一个字节来说明这一点;您可以使用移位将其扩展为整数。
uint8_t n = ... // Some value
n = n | (!n); // Here is the trick
最后一个操作将 0x00 转换为 0x01,而所有其他值(即 0x01 到 0xFF,包括在内)保持不变 (demo)。
* 位掩码的构造取决于对其应用的操作。对于 "AND" 和 "XOR",您将所需的位标记为 1,而对于 "OR",您将其标记为零。
我用谷歌搜索 "detect zero byte in word"。我建议你也这样做。
这个是无分支的,使用五个操作(至少在 C 中,机器代码指令的数量取决于您的编译器和平台,等等)。
我猜你赢不了多少,但为了好玩,这里是:
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
static void print(uint32_t x)
{
printf("0x%08" PRIX32 "\n", x);
}
int main()
{
uint32_t x;
x = 0xb300ff00; /* <- an example, should work with any 32 bit value */
print(x);
print(x - 0x01010101);
print((x - 0x01010101) & ~x);
print((x - 0x01010101) & ~x & 0x80808080);
print(((x - 0x01010101) & ~x & 0x80808080) >> 7);
print(x | ((x - 0x01010101) & ~x & 0x80808080) >> 7); /* <- the final result */
return 0;
}
编辑:
作为旁注,这是由编译器生成的:
leal -16843009(%rdi), %eax
movl %edi, %ecx
notl %ecx
andl %ecx, %eax
shrl , %eax
andl 843009, %eax
orl %edi, %eax
另一个旁注:这当然可以以相同的方式处理 64 位整数,并行处理八个字节,使用相同的几条指令。
比如我有以下号码:
0x FF 00 FF
现在,我希望 00 部分只有在它为 0 时才为 1。我需要检查每个字节还是有可以在这里使用的位技巧?
示例:
我有一个无符号长 IP,我用字符串函数对其进行哈希处理,但该函数终止于空字节,因此我需要将所有空字节设置为 1:
0x7F000001(127.0.0.1,可以是 0x0100007F,但取决于平台)
现在,我想将 0 字节变成 1:
0x7F010101(所以会变成127.1.1.1)
这是做我想做的唯一方法,这
char ip_sz[5];
*(unsigned long*)ip_sz = ulong_ip;
if (!ip_sz[0]) ip_sz[0] = 1;
if (!ip_sz[1]) ip_sz[1] = 1;
if (!ip_sz[2]) ip_sz[2] = 1;
if (!ip_sz[3]) ip_sz[3] = 1;
?
真的,好奇。我不关心性能,因为我知道编译器无论如何都会优化它。
您可以通过应用 位掩码 来检查整个字节是否为零(即在您希望检查的位置包含 1 而在所有其他位置包含零的数字*) 到它。
在你的情况下,你需要一个位掩码,在从零开始的位置 7 到 15(含)中有八个连续的 1,即 0x00FF00
。如果按位 "AND" &
应用于掩码和数字 n
,仅当位置 7 到 15 中 n
的所有位均为零时,结果才为零。否则,结果将是一些非零数。
int n = 0xFF00FF;
int mask = 0x00FF00;
if ((n & mask) == 0) {
... // Modify n as needed
}
您可以手动构造一个八位位掩码,或者使用左移运算符,如下所示:
(0xFF) // 0x000000FF
(0xFF << 8) // 0x0000FF00
(0xFF << 16) // 0x00FF0000
(0xFF << 24) // 0xFF000000
so, I would still have to do four
if
's?
在这种特定情况下,if
不是必需的,因为 C 中的一个小技巧:您可以使用 !
将零转换为一,将任何其他数字转换为零。我将用一个字节来说明这一点;您可以使用移位将其扩展为整数。
uint8_t n = ... // Some value
n = n | (!n); // Here is the trick
最后一个操作将 0x00 转换为 0x01,而所有其他值(即 0x01 到 0xFF,包括在内)保持不变 (demo)。
* 位掩码的构造取决于对其应用的操作。对于 "AND" 和 "XOR",您将所需的位标记为 1,而对于 "OR",您将其标记为零。
我用谷歌搜索 "detect zero byte in word"。我建议你也这样做。 这个是无分支的,使用五个操作(至少在 C 中,机器代码指令的数量取决于您的编译器和平台,等等)。 我猜你赢不了多少,但为了好玩,这里是:
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
static void print(uint32_t x)
{
printf("0x%08" PRIX32 "\n", x);
}
int main()
{
uint32_t x;
x = 0xb300ff00; /* <- an example, should work with any 32 bit value */
print(x);
print(x - 0x01010101);
print((x - 0x01010101) & ~x);
print((x - 0x01010101) & ~x & 0x80808080);
print(((x - 0x01010101) & ~x & 0x80808080) >> 7);
print(x | ((x - 0x01010101) & ~x & 0x80808080) >> 7); /* <- the final result */
return 0;
}
编辑:
作为旁注,这是由编译器生成的:
leal -16843009(%rdi), %eax
movl %edi, %ecx
notl %ecx
andl %ecx, %eax
shrl , %eax
andl 843009, %eax
orl %edi, %eax
另一个旁注:这当然可以以相同的方式处理 64 位整数,并行处理八个字节,使用相同的几条指令。