【C语法硬核20讲】15 位运算大全:掩码与移位

内容分享2个月前发布
1 2 0

目标:系统掌握 & | ^ ~ << >> 的语义与陷阱无符号优先掩码构造字段打包/解包按 2 的幂对齐位计数/低位索引等实战技巧。


【C语法硬核20讲】15 位运算大全:掩码与移位

1)无符号优先(避免实现定义行为)

  • 右移 >>:对有符号负数是实现定义(算术/逻辑右移不必定);
  • 提议:用无符号类型做移位与掩码:uint32_t/uint64_t。

2)基本操作速查

u &= mask;     // 保留
u |= mask;     // 置位
u ^= mask;     // 反转
u &= ~mask;    // 清零

构造单比特:(UINT32_C(1) << n);风险:n >= 位宽 → 未定义行为


3)字段打包/解包(协议友善)

// 布局: [31:29]=ver(3) [28:24]=type(5) [23:0]=len(24)
static inline uint32_t pack_hdr(uint32_t ver,uint32_t type,uint32_t len){
    return ((ver & 0x7u)  << 29) |
           ((type & 0x1Fu)<< 24) |
           (len & 0xFFFFFFu);
}
static inline void unpack_hdr(uint32_t x, uint32_t *ver,uint32_t *type,uint32_t *len){
    *ver  = (x>>29) & 0x7u;
    *type = (x>>24) & 0x1Fu;
    *len  = x & 0xFFFFFFu;
}

与大小端无关:我们在寄存器值上操作;跨网络请配合 htonl/ntohl。


4)对齐到 2 的幂(常用)

// 向上取整到 2^k
static inline uint32_t align_up_pow2(uint32_t x, uint32_t a){ // a 为 2 的幂
    return (x + (a-1)) & ~(a-1);
}
static inline uint32_t align_down_pow2(uint32_t x, uint32_t a){
    return x & ~(a-1);
}

5)位计数/最低位索引

  • 可移植做法:
static inline unsigned popcount_u32(uint32_t x){
    unsigned c=0; while(x){ x &= x-1; ++c; } return c;
}
static inline unsigned ctz_u32(uint32_t x){ // count trailing zeros
    unsigned n=0; if(!x) return 32;
    while((x & 1u)==0){ x >>= 1; ++n; } return n;
}
  • 如可用编译器内建:__builtin_popcount/__builtin_ctz(GCC/Clang),MSVC:_BitScanForward。

6)位标志枚举 + 掩码工具(与第 13 讲配套)

enum Feature { F_A=1u<<0, F_B=1u<<1, F_C=1u<<2 };
typedef unsigned FeatureMask;
#define F_SET(m,f)   ((m)|=(f))
#define F_CLR(m,f)   ((m)&=~(f))
#define F_HAS(m,f)   (((m)&(f))!=0)

7)常见坑

  1. 左移超位宽:1u << 32(在 32 位无定义)。
  2. 用有符号整型做右移。
  3. 忘记把常量声明为无符号:1 << n 参与提升后可能溢出。
  4. 用位域表达跨平台协议(布局/端序不可控)。

8)练习

  • 写 mask_range(lo, hi):生成 [lo, hi] 连续 1 的掩码;
  • 写 is_pow2(x) 与 next_pow2(x);
  • 实现 64 位的 popcount/ctz(优先用内建)。
© 版权声明

相关文章

2 条评论

  • 头像
    _苏小yu_ 投稿者

    收藏了,感谢分享

    无记录
    回复
  • 头像
    衣百万的一百万 投稿者

    👍👍

    无记录
    回复