unsigned long变量引发段错误之谜:为何size_t会导致系统崩溃?
其他进制转十进制C程序的段错误原因解析
#include<stdio.h> #include<string.h> #include<stdbool.h> #include<math.h> #include<stdlib.h> float other_to_decimal(char *n, unsigned int base) { float out = 0; size_t point_idx = 0,len = strlen(n); // 判断输入是否为负数 bool input_is_negative = (n[0] == '-') ? true : false; // 查找小数点的下标 while (point_idx != len && n[point_idx] != '.') point_idx++; // 判断是否存在小数部分 bool frac_part_exists = (point_idx == len || point_idx == len - 1) ? false : true; // 转换整数部分 const size_t end = input_is_negative ? 1 : 0; int power = 0; for (int i = point_idx - 1; i >= end; i--, power++) out += n[i] <= '9' ? (n[i] - '0') * pow(base, power) : (n[i] - 'A' + 10) * pow(base, power); // 转换小数部分 if(frac_part_exists) { power = -1; for (size_t i = point_idx + 1; i < len; i++,power--) out += n[i] <= '9' ? (n[i] - '0') * pow(base, power) : (n[i] - 'A' + 10) * pow(base, power); } out *= input_is_negative ? -1 : 1; return out; } int main(int argc, char const *argv[]) { printf("%f\n", other_to_decimal("1101.01", 2)); // 预期输出13.25 return 0; }
注:Linux环境编译需添加
-lm参数链接数学库
问题核心
这段代码原本会触发段错误,将第23行的const size_t end改为int end后程序恢复正常。明明end仅取值0或1,均在size_t(底层为unsigned long)的支持范围内,且仅参与比较操作,为何会引发崩溃?
原因解析
问题出在有符号与无符号整数的隐式类型转换上:
在C语言中,当有符号整数(int类型的i)和无符号整数(size_t类型的end)进行比较时,有符号整数会被强制转换为无符号整数类型。以示例中的非负输入为例:
- 循环从
point_idx-1(即3)开始递减,直到i变为-1。 - 此时执行
i >= end比较时,i=-1会被转换为无符号整数,对应一个极大的正数(比如64位系统下为18446744073709551615),远大于end=0。 - 循环不会终止,
i继续递减(作为有符号数会更小,但转成无符号数始终是极大值),导致访问数组n的下标越界,触发段错误。
当把end改为int类型后,i >= end是两个有符号整数的比较,i=-1时-1 >= 0不成立,循环正常终止,不会出现越界访问。
额外建议
- 循环变量的类型尽量保持统一,避免有符号与无符号类型混用引发的隐式转换问题。
- 处理字符串下标时,若涉及负数边界判断,建议使用有符号整数类型,或显式进行类型转换确保逻辑正确。
内容的提问来源于stack exchange,提问作者Soham Jobanputra
相关产品推荐
相关产品推荐

