仅当它为 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 位整数,并行处理八个字节,使用相同的几条指令。