C语言位运算计算异常:16位无符号短整数拆分为8位字符出错求助
16位无符号整数拆分为8位字符的问题定位、修复与优化
错误原因分析
- 有符号char的符号扩展:你定义的
charsToWrite为char类型,多数编译器中char默认是有符号的。第二个字节的二进制值是0b11110111(十进制247),赋值给有符号char时会被解析为负数(-9),用printf("%u")打印时,负数会被符号扩展为32位无符号数,从而出现4294967287的错误结果。 - pow函数的精度风险:用
pow(2, 8)计算掩码属于不必要的浮点操作,可能因浮点精度偏差导致错误,位运算场景应直接使用整数常量(如0xFF)。 - 掩码计算逻辑冗余:你写的掩码生成代码过于复杂,位移组合容易出现逻辑漏洞,不如直接针对高低位字节做简单位运算。
修复方案
方案1:修正类型并简化位运算
将存储拆分后字节的数组改为unsigned char避免符号扩展,同时简化位运算逻辑:
#include <stdio.h> int main() { int blocks = 1; unsigned short stuffToWrite[blocks]; stuffToWrite[0] = 0b0100101011110111; // 对应十进制19191 int charsPerBlock = sizeof(unsigned short) / sizeof(unsigned char); unsigned char charsToWrite[blocks * charsPerBlock]; // 使用unsigned char for (int i = 0; i < blocks; i++) { // 提取高位字节(大端顺序) charsToWrite[i * charsPerBlock] = (stuffToWrite[i] >> 8) & 0xFF; // 提取低位字节 charsToWrite[i * charsPerBlock + 1] = stuffToWrite[i] & 0xFF; // 测试输出 printf("%u = (%u >> 8) & 0xFF\n", charsToWrite[i*charsPerBlock], stuffToWrite[i]); printf("%u = %u & 0xFF\n", charsToWrite[i*charsPerBlock+1], stuffToWrite[i]); } // 写入二进制文件示例 FILE *fp = fopen("output.bin", "wb"); if (fp) { fwrite(charsToWrite, sizeof(unsigned char), blocks * charsPerBlock, fp); fclose(fp); } return 0; }
运行后会输出正确的74和247,符合预期。
方案2:兼容原循环结构的修正
如果要保留原循环结构,调整掩码计算并修改类型:
#include <stdio.h> int main() { int blocks = 1; unsigned short stuffToWrite[blocks]; stuffToWrite[0] = 0b0100101011110111; int charsPerBlock = sizeof(unsigned short) / sizeof(unsigned char); unsigned char charsToWrite[blocks * charsPerBlock]; for (int i = 0; i < blocks; i++) { for (int j = 0; j < charsPerBlock; j++) { // 直接生成对应位置的掩码,避免复杂位移组合 unsigned short mask = 0xFF << ((charsPerBlock - 1 - j) * 8); charsToWrite[i*charsPerBlock+j] = (stuffToWrite[i] & mask) >> ((charsPerBlock - 1 - j) * 8); printf("%u = (%u & %u) >> %d\n", charsToWrite[i*charsPerBlock+j], stuffToWrite[i], mask, (charsPerBlock - 1 - j)*8); } } return 0; }
更优实现方式
方式1:直接写入原数组(注意字节序)
如果不需要手动拆分字节,且接受系统原生字节序(小端/大端),可以直接用fwrite写入整个unsigned short数组,代码最简洁:
FILE *fp = fopen("output.bin", "wb"); if (fp) { fwrite(stuffToWrite, sizeof(unsigned short), blocks, fp); fclose(fp); }
注意:写入的字节顺序取决于系统架构(x86系列为小端,ARM可配置)。
方式2:明确处理字节序(跨平台兼容)
如果需要固定字节序(如网络字节序大端),可以用标准库函数htons转换后写入:
#include <stdio.h> #include <arpa/inet.h> // htons函数头文件 int main() { int blocks = 1; unsigned short stuffToWrite[blocks]; stuffToWrite[0] = 0b0100101011110111; FILE *fp = fopen("output.bin", "wb"); if (fp) { for (int i = 0; i < blocks; i++) { unsigned short be_val = htons(stuffToWrite[i]); // 转为大端字节序 fwrite(&be_val, sizeof(unsigned short), 1, fp); } fclose(fp); } return 0; }
htons会自动处理主机字节序到网络大端字节序的转换,保证跨平台兼容性。
内容的提问来源于stack exchange,提问作者Nasser Kessas
相关产品推荐
相关产品推荐

