这个功能如何工作?

时间:2013-11-21 05:58:05

标签: c

在阅读 Hacking:剥削艺术(一本精彩的书!)时,我遇到了这个功能:

void binary_print(unsigned int value) {
   unsigned int mask = 0xff000000; // Start with a mask for the highest byte.
   unsigned int shift = 256*256*256; // Start with a shift for the highest byte.
   unsigned int byte, byte_iterator, bit_iterator;

   for(byte_iterator=0; byte_iterator < 4; byte_iterator++) {
      byte = (value & mask) / shift; // Isolate each byte.
      printf(" ");
      for(bit_iterator=0; bit_iterator < 8; bit_iterator++) { // Print the byte's bits.
         if(byte & 0x80) // If the highest bit in the byte isn't 0,
            printf("1");       // print a 1.
         else
            printf("0");       // Otherwise, print a 0.
         byte *= 2;         // Move all the bits to the left by 1.
      }
      mask /= 256;       // Move the bits in mask right by 8.
      shift /= 256;      // Move the bits in shift right by 8.
   } 
}

这是函数的输入输出表:

= = = = = = = = = = = = = = = = = = = = = =
INPUT : OUTPUT
= = = = = = = = = = = = = = = = = = = = = =
0     : 00000000 00000000 00000000 00000000
2     : 00000000 00000000 00000000 00000010
1     : 00000000 00000000 00000000 00000001
1024  : 00000000 00000000 00000100 00000000
512   : 00000000 00000000 00000010 00000000
64    : 00000000 00000000 00000000 01000000
= = = = = = = = = = = = = = = = = = = = = =

据我所知,binary_print()将十进制转换为二进制。

但是我不明白 究竟该函数找到了正确的答案。具体做法是:

  • 什么是面具?作者是如何得到价值0xff000000的? (0xff000000似乎接近2 ^ 32,系统中int的最大值)
  • 什么是转变?为什么要将它初始化为256 ^ 3? (对我而言,似乎它与十六进制的位置权重有关)
  • 这些内容实际发生了什么:
    • byte =(value&amp; mask)/ shift
    • 字节&amp; 0x80的

简而言之,我想理解 binary_print()用来做的方法 转换。

3 个答案:

答案 0 :(得分:6)

作为一个位mask(在32位机器上)0xff000000具有最高字节的全1位。 shift初始化为0x1000000(即256 * 256 * 256)。

byte = (value & mask)/shift正在使用位 - 并提取掩码的位,然后将它们移位以获得介于0和0xff之间的值(适合8位字节)。

请注意,对于unsigned,数字mask /= 256mask = mask >> 8相同(并且编译器通常会优先考虑第一个到第二个)。

准确理解所发生情况的最佳方法是使用所有警告和调试信息(例如gcc -Wall -g)编译代码并使用使用调试器gdb )逐步运行程序并显示相关状态。

答案 1 :(得分:3)

这更多是评论而不是答案。我还没有看到这本书,所以我不知道该代码摘录应该展示什么,但它是一种高度精心设计的产生所需输出的方法。

这是一个更简单的一个:

void binary_print(unsigned value) {
  for (unsigned mask = 0x80000000;  // High order bit
       mask;                        // While we have a bit
       mask >>= 1) {                // Shift right to next bit position
    if (value & mask) putchar('1'); // Bit is set: print a 1
    else              putchar('0'); // Bit is not set: print a 0
    if (mask & 0x01010100) putchar(' '); // A space if we just did the
                                         // low order bit of some byte
  }
}

除了最后一行的黑客攻击之外,我希望,对于熟悉位操作的人来说,我认为逻辑应该非常简单。印刷技术是否过度

答案 2 :(得分:0)

我们以值为 1024 或 0x400 的 O_APPEND 为例:

如果您查看 byte_iterator 循环中的值,您可以看到掩码和移位值的变化:

byte_iterator: 0, mask: ff000000, shift: 1000000, byte: 0
byte_iterator: 1, mask: ff0000,   shift: 10000,   byte: 0
byte_iterator: 2, mask: ff00,     shift: 100,     byte: 4
byte_iterator: 3, mask: ff,       shift: 1,       byte: 0

maskvalue 与按位 AND 组合返回掩码为 'ff' 的字节,意味着第一个循环给出最高字节,最后一个循环返回最低字节。在这个例子中,我们有 O_APPEND,十六进制值为 00 00 04 00,第三个字节是 4,所有其他字节都是 0。

bit_iterator 循环中,使用的掩码是 0x80 或二进制 00001000:

loop number: 0, byte: 4,   byte & 0x80: 0
loop number: 1, byte: 8,   byte & 0x80: 0
loop number: 2, byte: 16,  byte & 0x80: 0
loop number: 3, byte: 32,  byte & 0x80: 0
loop number: 4, byte: 64,  byte & 0x80: 0
loop number: 5, byte: 128, byte & 0x80: 80
loop number: 6, byte: 256, byte & 0x80: 0
loop number: 7, byte: 512, byte & 0x80: 0

第 6 个循环返回一个值 != 0,因此该字节被打印为 00000100 等于 0x4。