我有一个值为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,并将第一个和第二个字节拆分为单独的字符。感谢。
答案 0 :(得分:5)
直接来自Wikipedia:
#define HI_NIBBLE(b) (((b) >> 4) & 0x0F)
#define LO_NIBBLE(b) ((b) & 0x0F)
所以HI_NIBBLE(addr)
将是0xB
。但是,0x00
到0xFF
不是“双字节”。它们是单字节值。单个十六进制数字可以占用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);