C语言K&R习题2-1:变量类型范围计算bug及void*使用合法性咨询
K&R习题2-1相关问题解答
1. 最大值计算结果比预期小1的问题
问题出在所有位操作函数的循环终止条件:你写的是while(bit),当bit递减到0时循环直接终止,最低有效位(对应bit=0)永远不会被处理,所以最终结果永远比正确值小1。
修复方案:将所有循环条件改为while(bit >= 0)即可。
另外你的代码中存在大量无效操作:
- 无符号类型最小值恒为0,
unsigned_min函数里的位操作完全多余,直接给目标变量赋值0即可 signed_min、signed_max中的|= 0 << bit操作不会改变变量值,属于冗余代码,可以直接删除
2. void强转size_t的合法性及替代方案
合法性判断
该操作不符合C语言标准,属于未定义行为:
- size_t的长度是平台相关的(32位系统为4字节、64位系统为8字节),当你传入的变量长度小于size_t长度时,解引用
size_t*指针会访问变量所属内存之外的地址,可能会篡改其他变量的值、触发段错误,只是当前测试场景下刚好没触发异常而已 - 该写法还存在严格别名规则违规问题,C标准不允许通过不兼容的指针类型访问对象
替代方案(无运行时循环开销)
方案1:使用C11泛型_Generic
编译期根据传入参数类型自动匹配处理逻辑,完全无运行时开销,示例代码片段:
#define unsigned_max(x) _Generic((x), \ unsigned char: (x) = UCHAR_MAX, \ unsigned short: (x) = USHRT_MAX, \ unsigned int: (x) = UINT_MAX, \ unsigned long: (x) = ULONG_MAX \ )
方案2:逐字节操作(兼容C89标准)
将void*转为unsigned char*按字节赋值,仅需要循环等于类型长度的次数(最长8次,几乎无开销):
void unsigned_max(void* data_ptr, size_t data_size) { unsigned char* p = (unsigned char*)data_ptr; for (size_t i=0; i<data_size; i++) p[i] = 0xff; }
3. 单行极值计算方案出错的原因
你写错了常量:C语言中-0和0完全等价,所以(unsigned char)-0的结果就是0,后续操作自然全部返回0。你需要将-0改为-1:无符号类型接收-1赋值时,会自动转换为该无符号类型的最大值(所有位全1),符合你的预期。
修复后的代码:
printf("signed char min = %d\n", -(char)((unsigned char)-1 >> 1)); printf("signed char max = %d\n", (char)((unsigned char)-1 >> 1)); printf("unsigned char max = %u\n", (unsigned char)-1);
另外你提到的反码-0问题:当前主流通用计算设备全部使用补码表示整数,补码中不存在-0,-0和0的二进制表示完全一致,所以你假设的-0对应全1位的情况在补码系统中不存在。
内容的提问来源于stack exchange,提问作者user15480998
相关产品推荐
相关产品推荐

