在C中评估一个字节的段

问题描述 投票:1回答:3

我试图在不使用反汇编表的情况下对Intel 8080进行反汇编。我读取内存字节并将它们分成比特的部分:(7,6),(5,4,3),(2,1,0)。我想知道这些部分的数值是什么,这是一个例子:

给出这个字节:

0b00110000

第7位和第6位评估为:

0b00 -> 0

第5到3位:

0b110 -> 6

位2到0:

0b000 -> 0

现在,我对C非常缺乏经验,我很难想出一个优雅而简单的解决方案来解决这个问题。到目前为止,我的想法如下:

  1. 创建3个字节副本(每个部分1个)
  2. 清除除我感兴趣的位之外的所有位(按位AND掩码)
  3. 将字节移位适当的位数
  4. 读取值

这会完成这项工作还是有更好的方法?

c bit-manipulation
3个回答
2
投票

如果你考虑需要做什么,你只需要关注一元>>移位算子和&算子。它还有助于提出一个位掩码,以便根据可能需要的任何中间计算仅隔离那些所需的位。 (位掩码只是一个包含数字的变量,其1位和0位可用于按位运算,以便为您提供所需的结果)。

在这里,在所有的位分离中,在转换到最终结果后,您将只关注2或3个低位。在你正在查看(7,6)的情况下,没有其他位可以屏蔽,只留下你正在查看需要掩码的低3位的情况。

从位掩码(或神奇数字)的角度来看,您需要一个掩码来保留最后的3位并丢弃所有剩余的高位。因此,对于8位值,您需要00000111,或者只需要数字7

首先,如果要检查8位数中的最高2位,则只需将数字向qamxswpoi移动到右侧,例如给出一个字节6在你的情况下持有总值b,你需要。

0x00110000

这里不需要屏蔽任何东西,因为没有更高的位。

对于你的例子中的b >> 6; 位,你需要通过(5,4,3)向右移动,然后你需要用你的3&mask7中间结果来摆脱保留b00000111的两位,例如

(6,7)

在最后一部分,你的uint8_t mask = 7; ... (b >> 3) & mask; 位,不需要移位,你只需要消除位(2,1,0)上的所有位,例如,用你的面具摆脱2

(7,6,5,4,3)

完全放置,使用精确的宽度类型,您可以执行类似于以下操作。程序将您的字节值作为其第一个参数(使用b & mask ,例如,如果没有给出参数,则默认为48)并输出移位和掩码的结果:

0x0011000

示例使用/输出

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>

int main (int argc, char *argv[]) {

    uint64_t tmp = argc > 1 ? strtoul (argv[1], NULL, 0) : 48;
    uint8_t b = 0,
        mask = 7;

    if (tmp > UINT8_MAX) {
        fprintf (stderr, "input exceeds UINT8_MAX.\n");
        return 1;
    }

    b = (uint8_t)tmp;

    printf ("(7,6)   0x%02" PRIx8 "\n", b >> 6);
    printf ("(5,4,3) 0x%02" PRIx8 "\n", (b >> 3) & mask);
    printf ("(2,1,0) 0x%02" PRIx8 "\n", b & mask);

    return 0;
}

仔细看看,如果您有其他问题,请告诉我。


1
投票

为了解析二进制值的特定位,我们使用位移和位掩码。可以使用以下概念以这种方式获得任何比特段:

$ /bin/bytes_233
(7,6)   0x00
(5,4,3) 0x06
(2,1,0) 0x00

其中(data >> n) & mask 是原始数据,data是此数据开始的位位置,n是“所有1”的位掩码,对应于段的长度。

“所有人”的mask可以从知道片段大小获得:mask。如果段的大小例如是3位,则1 << 3给出1000b。 1000b - 1 = 111b,这是3位的“全1”掩码。

因此,如果我们知道位的大小和位位置(偏移量),我们就可以得到数据。例:

(1u << size) - 1

带有“X宏”的高级版本,以避免代码重复:

#include <stdio.h>
#include <inttypes.h>

#define SEG1_BITS   2
#define SEG1_OFFSET 6
#define SEG2_BITS   3
#define SEG2_OFFSET 3
#define SEG3_BITS   2
#define SEG3_OFFSET 0

#define SEG1(d) ( ((uint32_t)d >> SEG1_OFFSET) & ((1u<<SEG1_BITS)-1) )
#define SEG2(d) ( ((uint32_t)d >> SEG2_OFFSET) & ((1u<<SEG2_BITS)-1) )
#define SEG3(d) ( ((uint32_t)d >> SEG3_OFFSET) & ((1u<<SEG3_BITS)-1) )

int main (void)
{
  uint8_t data = 0x30;

  printf("%"PRIu32"\n", SEG1(data));
  printf("%"PRIu32"\n", SEG2(data));
  printf("%"PRIu32"\n", SEG3(data));
  return 0;
}

0
投票

由于问题证明是广泛的,我不得不概括它并编写这个方法:

#include <stdio.h>
#include <inttypes.h>

#define SEG_LIST     \
  /*bits, offset */  \
  X(2,    6)         \
  X(3,    3)         \
  X(2,    0)

#define SEG(data, bits, n) ( ((uint32_t)data >> n) & ((1u<<bits)-1) )

int main (void)
{
  uint8_t data = 0x30;

  #define X(bits, n) printf("%"PRIu32"\n", SEG(data, bits, n));
    SEG_LIST
  #undef X

  return 0;
}

它将从字节的连续段中提取值。

© www.soinside.com 2019 - 2024. All rights reserved.