You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言位运算计算异常:16位无符号短整数拆分为8位字符出错求助

16位无符号整数拆分为8位字符的问题定位、修复与优化

错误原因分析

  1. 有符号char的符号扩展:你定义的charsToWrite为char类型,多数编译器中char默认是有符号的。第二个字节的二进制值是0b11110111(十进制247),赋值给有符号char时会被解析为负数(-9),用printf("%u")打印时,负数会被符号扩展为32位无符号数,从而出现4294967287的错误结果。
  2. pow函数的精度风险:用pow(2, 8)计算掩码属于不必要的浮点操作,可能因浮点精度偏差导致错误,位运算场景应直接使用整数常量(如0xFF)。
  3. 掩码计算逻辑冗余:你写的掩码生成代码过于复杂,位移组合容易出现逻辑漏洞,不如直接针对高低位字节做简单位运算。

修复方案

方案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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 11:15:44