使用位移位操作实现2字节日期编解码的C语言问题排查
问题解决:仅用移位操作完成日期的编解码
问题根源
你当前解码月、日失败的核心原因是:unsigned int在32位编译环境下为32位宽度,左移操作不会自动丢弃高位的年份数据,后续右移时会带入这些无效位,导致结果错误。
根据你的编码逻辑,16位编码的位分配如下:
- 年份偏移值(
year-1980):占据高7位(bit9 ~ bit15) - 月份:占据中间4位(bit5 ~ bit8)
- 日期:占据低5位(bit0 ~ bit4)
修正后的代码方案(通用32位版本)
// Date encoding in 2-byte number #include <stdio.h> #include <conio.h> typedef unsigned int uint; #define BITS_PER_UINT (sizeof(uint) * 8) void Showbits(uint n) // 修正参数类型为uint,避免符号位干扰 { int i, k, mask; for (i = 15; i >= 0; i--) { mask = 1 << i; k = n & mask; printf("%c", k ? '1' : '0'); } } int main() { uint encd_date, date, month, year; year = 2022; month = 9; date = 15; encd_date = 512 * (year - 1980) + 32 * month + date; printf("\nEncoded date: %u\n", encd_date); printf("\nencd_date: "); Showbits(encd_date); // 年份解码:右移9位,直接提取高7位 year = 1980 + (encd_date >> 9); // 月份解码:先右移5位将月份移到低4位,再通过移位清除高位无效数据 month = encd_date >> 5; month = month << (BITS_PER_UINT - 4); month = month >> (BITS_PER_UINT - 4); // 日期解码:左移27位清除高27位,再右移27位保留低5位 date = encd_date << (BITS_PER_UINT - 5); date = date >> (BITS_PER_UINT - 5); printf("\ndate: "); Showbits(date); printf("\nmonth: "); Showbits(month); printf("\nyear: "); Showbits(year); printf("\nDecoded date %u month %u year %u\n", date, month, year); return 0; }
简化方案(利用16位截断)
如果确定仅使用16位存储编码结果,可以将encd_date强制转换为unsigned short,利用16位宽度自动截断高位,简化移位操作:
// 解码部分替换为: year = 1980 + ((unsigned short)encd_date >> 9); month = (unsigned short)(encd_date << 7) >> 12; // 左移7位丢弃高7位年份,再右移12位提取月份 date = (unsigned short)(encd_date << 11) >> 11; // 左移11位丢弃高11位,再右移11位提取日期
关键说明
- 移位操作仅对
unsigned类型使用逻辑移位(右移补0),确保符号位不会干扰结果。 - 通用方案通过"移位+反移位"的组合彻底清除无关高位,适配不同宽度的
unsigned int类型。 - 简化方案依赖16位截断特性,仅适用于编码结果不超过16位的场景(你的日期编码逻辑正好符合)。
内容的提问来源于stack exchange,提问作者nascent
相关产品推荐
相关产品推荐

