C strtoul 函数
最后修改:2025 年 4 月 8 日
字符串到数字的转换是 C 编程中的一项常见任务,而 strtoul 是将字符串转换为无符号长整型的强大函数。本教程将深入介绍 strtoul,包括其语法、用法和错误处理。我们将探讨实际示例,并讨论为什么 strtoul 比 atoi 等函数更安全。理解 strtoul 有助于创建更可靠、更安全的字符串解析代码。
什么是 strtoul?
strtoul 函数将字符串转换为无符号长整型。它在 stdlib.h 中声明,并提供强大的错误处理。与 atoi 不同,它可以检测转换错误并支持不同的基数。该函数接受三个参数:要转换的字符串、一个用于存储结束位置的可选指针以及数字基数(2 到 36)。在生产代码中,请始终优先使用 strtoul 而不是 atoi。
strtoul 的基本用法
此示例演示了将简单的十进制字符串转换为无符号长整型。
#include <stdio.h>
#include <stdlib.h>
int main() {
const char *str = "12345";
char *endptr;
unsigned long value = strtoul(str, &endptr, 10);
if (*endptr != '\0') {
printf("Conversion error at: %s\n", endptr);
return 1;
}
printf("Converted value: %lu\n", value);
return 0;
}
在此,strtoul 将字符串 "12345" 转换为无符号长整型。我们使用基数 10(十进制)并检查 endptr 以获取转换错误。如果转换成功,endptr 将指向字符串的 null 终止符。这种基本模式对于安全字符串转换至关重要。始终检查 endptr 以检测部分转换。
十六进制转换
使用基数 16 时,strtoul 可以转换十六进制字符串。
#include <stdio.h>
#include <stdlib.h>
int main() {
const char *hex_str = "0x1a3f";
char *endptr;
unsigned long value = strtoul(hex_str, &endptr, 16);
if (*endptr != '\0' && *endptr != '\n') {
printf("Conversion error at: %s\n", endptr);
return 1;
}
printf("Hex value: %lu (0x%lx)\n", value, value);
return 0;
}
此示例将十六进制字符串 "0x1a3f" 转换为无符号长整型。基数 16 告诉 strtoul 将字符串解释为十六进制。请注意,使用基数 16 时 "0x" 前缀是可选的。该函数还可以同样处理大写十六进制数字(A-F)和小写字母(a-f)。十六进制转换通常用于解析内存地址或位掩码值。
strtoul 的错误处理
此示例演示了 strtoul 的全面错误处理。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
int main() {
const char *str = "99999999999999999999";
char *endptr;
unsigned long value;
errno = 0;
value = strtoul(str, &endptr, 10);
if (errno == ERANGE) {
printf("Value out of range\n");
return 1;
}
else if (*endptr != '\0') {
printf("Invalid character at: %s\n", endptr);
return 1;
}
printf("Converted value: %lu\n", value);
return 0;
}
此代码展示了 strtoul 的正确错误处理。我们检查 errno 以处理范围错误,并检查 endptr 以处理无效字符。大数字将触发 ERANGE,因为它超出了 ULONG_MAX。始终在调用 strtoul 之前将 errno 设置为 0,以区分 0 作为有效结果还是错误。这种模式对于健壮的字符串解析至关重要。
自动基数检测
使用 0 时,strtoul 可以自动检测数字基数。
#include <stdio.h>
#include <stdlib.h>
int main() {
const char *decimal = "12345";
const char *hex = "0x1a3f";
const char *octal = "0755";
char *endptr;
printf("Decimal: %lu\n", strtoul(decimal, &endptr, 0));
printf("Hex: %lu\n", strtoul(hex, &endptr, 0));
printf("Octal: %lu\n", strtoul(octal, &endptr, 0));
return 0;
}
当指定基数 0 时,strtoul 会像 C 字面量一样解释字符串:前导 "0x" 表示十六进制,前导 "0" 表示八进制,否则表示十进制。这与 C 编译器解释数字常量的方式相匹配。自动基数检测很方便,但可能不如直接指定基数明确。当您需要解析各种格式的数字时,可以使用此功能。
解析多个数字
此示例展示了如何使用 strtoul 和 endptr 从字符串中解析多个数字。
#include <stdio.h>
#include <stdlib.h>
int main() {
const char *str = "10 20 30 40";
char *endptr = (char *)str;
while (*endptr != '\0') {
unsigned long value = strtoul(endptr, &endptr, 10);
if (endptr == str) {
break; // No conversion performed
}
printf("Parsed: %lu\n", value);
// Skip whitespace
while (*endptr == ' ') {
endptr++;
}
}
return 0;
}
此代码从空格分隔的字符串中解析多个无符号整数。每次转换后,endptr 将指向下一个字符,从而实现顺序解析。我们手动跳过数字之间的空格。此技术对于解析输入文件或命令行参数很有用。请注意检查 endptr == str 以检测何时未发生转换。
使用 strtoul 的最佳实践
- 始终检查 endptr: 验证转换停止的位置。
- 重置 errno: 调用前设置为 0,以检测范围错误。
- 优先于 atoi:
strtoul具有更好的错误处理。 - 选择合适的基数: 在需要时使用 0 进行自动检测。
- 验证输入: 检查空字符串或 NULL 指针。
来源
本教程从基本用法到高级解析技术,对 strtoul 函数进行了探讨。正确的字符串转换对于安全可靠的 C 程序至关重要。始终优先使用 strtoul 而不是更简单但安全性较差的替代方法(如 atoi)。
作者
列表 C 标准库。