0

我有一个值 char 说 0xB3,我需要把它分成两个单独的 char。所以 X = 0xB 和 Y = 0x3。我试过以下代码:

int main ()
{
    char addr = 0xB3;
    char *p = &addr;

    printf ("%c, %c\n", p[0], p[1]);          //This prints ?, Y
    printf ("%X, %X\n", p[0], p[1]);          //This prints FFFFFFB3, 59

    return 0;
}

为了澄清起见,我需要将值 00 的任何 2 字节字符转换为 FF,并将第一个和第二个字节分成单独的字符。谢谢。

4

4 回答 4

5

直接来自维基百科

#define HI_NIBBLE(b) (((b) >> 4) & 0x0F)
#define LO_NIBBLE(b) ((b) & 0x0F)

HI_NIBBLE(addr)也会如此0xB。但是,0x00通过0xFF不是“双字节”。它们是单字节值。一个十六进制数字可以占用 16 个字节,而一个字节可以占用 256 = 16² 个字节,因此您需要两个十六进制数字来表示任意字节值。

于 2012-11-09T16:34:37.707 回答
1

这里有很多问题,让我们看一下您的代码:

int main ()
{
    char addr = 0xB3;  <-- you're asigning 0xB3 in hex, which is (179 in dec) to addr
    char *p = &addr;   <-- you're assigning a pointer to point to addr

如果addr是无符号的,现在将设置为 179,即扩展ASCII│ ( Box drawing character )

如果char有符号,则值可以是 -127 到 +127,如果没有符号,则可以是 0 到 255。在这里(根据您的输出)它已签名,因此您的char分配溢出了。

printf ("%c, %c\n", p[0], p[1]); <-- print the char value of what p is pointing to
                                     also, do some UB
printf ("%X, %X\n", p[0], p[1]); <-- print the hex value of  what p is pointing to
                                     also, do some UB

因此,您的代码的第二部分在这里打印溢出addrvar 的 char 值,它恰好'?'为您打印。的十六进制值addr表示FFFFFFB3您有一个负值(最高位是有符号位)。

this:p[0]实际上是一个“加法和引用”运算符。这意味着我们将获取 的地址p,添加0到它,然后遵从并查看结果:

p ---------+
           V
       ------------------------------------------
      | ptr(0xB3) |    ?      |     ?     | ... |
      -------------------------------------------
       0xbfd56c2b  0xbfd56c2C  0xbfd56c2d   ...      

当你这样做时,p[1]会超过 ptr 一个char或一个字节并给你那个结果。什么东西在那里?不知道。这超出了您的范围:

p+1 -------------------+
                       V
       ------------------------------------------
      | ptr(0xB3) |    ?      |     ?     | ... |
      -------------------------------------------
       0xbfd56c2b  0xbfd56c2C  0xbfd56c2d   ...   

Y的 ASCII 值(十六进制)是 0x59,所以内存中的指针后面是Y. 但它可能是任何东西,将要做什么是未定义的。正确的方法是:

int main ()
{
    unsigned char addr = 0xB3;
    char low = addr & 0x0F;
    char high = (addr >> 4) & 0x0F;

    printf("%#x becomes %#x and %#x\n", addr, high, low);

    return 0;
}

这通过以下方式工作:

    0xB3  =>  1011 0011        0xB3 >> 4 =   0000 1011
            & 0000 1111                    & 0000 1111
            ------------                  -------------
              0000 0011 => 3 low             0000 1011 => B high
于 2012-11-09T17:26:42.280 回答
0

为什么需要通过指针传递?只需取 4 个相关位并在需要时移动最有意义的位:

char lower = value & 0x0F;
char higher = (value >> 4) & 0x0F;

然后0xB3是一个字节,而不是两个字节。因为一个十六进制数字可以有 16 个值,所以两个数字可以存储 16*16 = 256 个值,这就是你可以在一个字节中存储多少。

于 2012-11-09T16:35:11.107 回答
0

好的,所以您尝试将 0xB3 拆分为 0xB 和 0x3,仅供参考,不要说“字节字符”,一个字节的 2 个部分通常称为“半字节”,一个字节由 2 个半字节组成(它们是由 4 位组成)。如果你不知道,char指的是 1 个字节。

因此,您的代码存在问题:

char addr = 0xB3;  <---- Creates single byte with value 0xB3 - Good
char *p = &addr;   <---- Creates pointer pointing to 0xB3 - Good

printf ("%c, %c\n", p[0], p[1]); <---- p[0], p[1] - Bad
printf ("%X, %X\n", p[0], p[1]); <---- p[0], p[1] - Bad

好的,所以当您引用p[0]p[1]告诉系统指针p指向 s 数组时char(p[0] 将引用 0xB3 但 p[1] 将指向内存中的下一个字节)

示例:这是您的系统内存的样子(但有 8 个字节的指针)

     Integer Values Area              Pointers Area
0x01 0x02 0x03 0x04 0x05 0x06    0x12 0x13 0x14 0x15 0x16
-----------------------------    ------------------------
.... .... 0xB3 0x59 .... ....    .... .... 0x03 .... ....
-----------------------------    ------------------------
           ^    ^                           ^
          addr  |                           p (example pointer pointing to example address 0x03)
             Random number                    (Pointers are normally 8 Bytes but)
             showing up in p[1]               (But In this example I used single bytes)

因此,当您告诉系统获取p[0]*p(它们会做同样的事情)时,它将转到地址(例如 0x03)并在这种情况下获取一个字节(因为它是一个字符)0xB3。但是,当您尝试时p[1]*(p+1)它将转到地址(例如 0x03),跳过第一个char并获取下一个给我们的地址,该地址0x59将用于其他变量。

好的,所以我们已经解决了这个问题,那么您如何获得小食呢?

获取半字节的一个问题是您通常不能只有半字节的 put 变量,没有仅支持 4 位的类型。当您使用 %x/%X 打印时,它只会显示直到最后一个非零数字的半字节,例如。= 0x00230242 只会显示 230242 但如果你做类似的事情

%2lX 将显示 2 个完整字节(包括零) %4lX 将显示 4 个完整字节(包括零)

因此,尝试获取单个小食是毫无意义的,但是如果您想做类似的事情,请执行以下操作:

char addr = 0x3B;
char addr1 = ((addr >> 4) & 0x0F);
char addr2 = ((addr >> 0) & 0x0F);
于 2018-10-08T06:05:28.127 回答