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

C语言signed char移位结果异常的原因及内存机制问询

问题原因与内存运作机制解析

问题重现

你的代码试图从字节数组中提取最后两个字节拼接成16位无符号整数,但在GCC下得到的结果是0xFFFF而非预期的0x11FF。代码如下:

#include <stdio.h>
#include <stdint.h>

int main()
{
    char msg[] = {0x01, 0x02, 0x03, 0x04, 0x11, 0xFF};
    uint16_t val;

    #define SIZE 6
    val = (msg[SIZE-2] << 8) | msg[SIZE-1];

    printf("%u\n", val);
    return 0;
}

核心原因:char的符号性与整数提升

GCC默认将char视为有符号类型,这是问题的根源:

  1. 数组最后一个元素0xFF作为有符号char,二进制全1(最高位为1),按补码规则会被解释为**-1**。
  2. C语言规定,char、short这类小整数类型参与运算时会自动触发整数提升:转换为int类型(32位系统下是4字节)。
    • 有符号数提升时会做符号扩展:0xFF对应的有符号char是-1,提升为int后变成0xFFFFFFFF(所有高位补1,保证数值仍为-1)。
  3. 位运算过程:
    • msg[SIZE-2]是0x11,提升为int后是0x00000011,左移8位得到0x00001100。
    • 和0xFFFFFFFF做按位或运算,结果为0xFFFFFFFF。
    • 赋值给uint16_t类型的val时,会截断为低16位,也就是0xFFFF。

内存运作机制

内存中存储的0xFF本身是8位二进制11111111,没有符号属性:

  • 当作**有符号char**读取时,最高位被视为符号位,按补码规则解析为-1;
  • 当作**unsigned char**读取时,直接将8位二进制解析为无符号数值255(0xFF)。

整数提升阶段的差异直接影响后续运算:

  • 无符号char提升为int时会做零扩展,0xFF变成0x000000FF,和0x1100按位或后得到0x11FF,赋值给uint16_t就是正确结果。

修复原理

将msg的类型改为unsigned char后,数组中的0xFF会被当作无符号值处理,整数提升时高位补0而非补1,位运算结果符合预期,最终得到正确的0x11FF。

内容的提问来源于stack exchange,提问作者gx16

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 06:37:17