将两个字节的char分成两个单字节字符

时间:2012-11-09 16:32:16

标签: c char

我有一个值为0xB3的char,我需要将它分成两个单独的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 个答案:

答案 0 :(得分:5)

直接来自Wikipedia

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

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

答案 1 :(得分: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,│ ( Box drawing character )的{​​{3}}

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

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

这:p[0]实际上是一个“添加和遵守”运算符。这意味着我们将采用p的地址,向其添加0,然后尊重并查看结果:

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

执行p[1]时,这会超过p {1}或一个字节,并为您提供结果。什么东西在那里?不知道。这超出了你的范围:

char

p+1 -------------------+ V ------------------------------------------ | ptr(0xB3) | ? | ? | ... | ------------------------------------------- 0xbfd56c2b 0xbfd56c2C 0xbfd56c2d ... 的ASCII值(十六进制)为0x59,因此在内存中指针后面是Y。但它可能是任何东西,未来的目标是未定义的。一个正确的方法是:

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;
}

答案 2 :(得分:0)

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

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

然后0xB3是一个字节,而不是两个字节。由于十六进制数字可以有16个值,因此两个数字可以存储16 * 16 = 256个值,这是您可以在一个字节中存储的数量。

答案 3 :(得分: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指向char s数组(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);