如何根据整数符号进行左移或右移位操作?
支持正负移位计数的通用移位实现
宏定义方案(类型无关,兼容所有C标准)
直接通过条件判断选择左移或右移操作,无需提前知晓x的类型:
#define SHIFT(x, b) ((b) > 0 ? ((x) << (b)) : ((b) < 0 ? ((x) >> -(b)) : (x)))
细节说明
- 当
b=0时直接返回原数,符合无操作的需求;b>0执行左移,b<0取绝对值后执行右移。 - 对于有符号类型的右移,C语言默认是算术右移(高位补符号位);如果需要逻辑右移(高位补0),可以先将
x转为无符号类型:#define LOGICAL_SHIFT(x, b) ((b) > 0 ? ((x) << (b)) : ((b) < 0 ? ((unsigned)(x) >> -(b)) : (x))) - 必须保证
|b|小于x类型的位数(比如32位int不能移32位及以上),否则属于未定义行为。
内联函数方案(C11+,更安全)
用_Generic适配不同整数类型,同时避免宏展开的副作用(比如x是表达式时重复计算):
#include <stdint.h> static inline intmax_t shift_signed(intmax_t x, int b) { return b > 0 ? x << b : (b < 0 ? x >> -b : x); } static inline uintmax_t shift_unsigned(uintmax_t x, int b) { return b > 0 ? x << b : (b < 0 ? x >> -b : x); } #define SHIFT(x, b) _Generic((x), \ intmax_t: shift_signed, \ uintmax_t: shift_unsigned, \ short: shift_signed, \ unsigned short: shift_unsigned, \ int: shift_signed, \ unsigned int: shift_unsigned, \ long: shift_signed, \ unsigned long: shift_unsigned, \ long long: shift_signed, \ unsigned long long: shift_unsigned, \ default: shift_signed((intmax_t)(x), b) \ )((x), (b))
优势
- 自动区分有符号/无符号类型,匹配对应的移位逻辑;
- 内联函数的形式减少了宏的潜在风险(比如参数重复求值)。
可选的安全校验
可以添加断言来确保移位计数在合法范围内,避免未定义行为:
#include <assert.h> #define SHIFT(x, b) \ (assert((b) >= -(int)(sizeof(x)*8) && (b) <= (int)(sizeof(x)*8)), \ (b) > 0 ? ((x) << (b)) : ((b) < 0 ? ((x) >> -(b)) : (x)))
内容的提问来源于stack exchange,提问作者SRobertJames
相关产品推荐
相关产品推荐

