通过char指针提取16位数据的8位输出异常,寻求技术帮助
问题分析与解决方案
你的问题核心出在有符号char的符号扩展和内存字节序两个点上,咱们一步步拆解:
1. 为什么会出现FFFFFF前缀?
大部分编译器默认char是有符号类型(signed char),它的取值范围是-128~127。当你用char*去解引用内存中的字节时:
- 如果字节值在
0x80~0xFF之间(比如0xAA、0xBB),会被当作负数(比如0xAA对应的有符号char值是-86) - 在调用
printf("%X")时,这个char会被自动提升为int类型,负数的符号扩展会把高位全部补1,就出现了FFFFFFAA这种输出。 - 而
0x34、0x12这类小于0x80的字节,作为有符号char是正数,提升为int时高位补0,所以输出正常。
2. 为什么字节顺序和预期不符?
这是小端字节序导致的:大部分现代CPU是小端模式,存储unsigned short时会把低字节放在内存低地址,高字节放在高地址。比如0xCCBB会被存成0xBB(低地址)、0xCC(高地址),所以你用char*遍历的时候会先拿到0xBB,再拿到0xCC,和你预期的CC在前、BB在后相反。
解决方案
方案一:改用unsigned char*遍历(最直接)
把指针类型改成无符号字符指针,这样解引用得到的字节不会被当作负数,提升为int时高位补0,彻底避免符号扩展:
#include <stdio.h> int main() { unsigned short int buf[50] = {0}; unsigned char *ptr = (unsigned char*)buf; // 替换为unsigned char* buf[0] = 0xAAAA; buf[1] = 0xCCBB; buf[2] = 0x1234; buf[3] = 0xABCD; for(int j = 0; j < 8; j++) { printf("%X\t", *ptr); ptr++; } return 0; }
输出结果(小端环境下):AA AA BB CC 34 12 CD AB
方案二:强制转换为无符号字符输出
如果不想改指针类型,在printf时把解引用的值强制转成unsigned char,同样能避免符号扩展:
printf("%X\t", (unsigned char)*ptr);
方案三:按16位数据的高位到低位输出(修正字节序)
如果你的目标是先输出每个unsigned short的高字节,再输出低字节,而不是按内存存储顺序遍历,可以直接操作16位数据:
#include <stdio.h> int main() { unsigned short int buf[50] = {0}; buf[0] = 0xAAAA; buf[1] = 0xCCBB; buf[2] = 0x1234; buf[3] = 0xABCD; for(int j = 0; j < 4; j++) { // 提取高8位:右移8位后转无符号char printf("%X\t", (unsigned char)(buf[j] >> 8)); // 提取低8位:与0xFF掩码后转无符号char printf("%X\t", (unsigned char)(buf[j] & 0xFF)); } return 0; }
输出结果:AA AA CC BB 12 34 AB CD,完全符合你对每个16位数据的高位到低位输出预期。
内容的提问来源于stack exchange,提问作者Sanith369
相关产品推荐
相关产品推荐

