ZetCode

C strtoul 函数

最后修改:2025 年 4 月 8 日

字符串到数字的转换是 C 编程中的一项常见任务,而 strtoul 是将字符串转换为无符号长整型的强大函数。本教程将深入介绍 strtoul,包括其语法、用法和错误处理。我们将探讨实际示例,并讨论为什么 strtoulatoi 等函数更安全。理解 strtoul 有助于创建更可靠、更安全的字符串解析代码。

什么是 strtoul?

strtoul 函数将字符串转换为无符号长整型。它在 stdlib.h 中声明,并提供强大的错误处理。与 atoi 不同,它可以检测转换错误并支持不同的基数。该函数接受三个参数:要转换的字符串、一个用于存储结束位置的可选指针以及数字基数(2 到 36)。在生产代码中,请始终优先使用 strtoul 而不是 atoi

strtoul 的基本用法

此示例演示了将简单的十进制字符串转换为无符号长整型。

basic_conversion.c
#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 可以转换十六进制字符串。

hex_conversion.c
#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 的全面错误处理。

error_handling.c
#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 可以自动检测数字基数。

auto_base.c
#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 编译器解释数字常量的方式相匹配。自动基数检测很方便,但可能不如直接指定基数明确。当您需要解析各种格式的数字时,可以使用此功能。

解析多个数字

此示例展示了如何使用 strtoulendptr 从字符串中解析多个数字。

multiple_numbers.c
#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 的最佳实践

来源

C strtoul 文档

本教程从基本用法到高级解析技术,对 strtoul 函数进行了探讨。正确的字符串转换对于安全可靠的 C 程序至关重要。始终优先使用 strtoul 而不是更简单但安全性较差的替代方法(如 atoi)。

作者

我叫 Jan Bodnar,我是一名敬业的程序员,对编码充满热情。自 2007 年以来,我通过 1400 多篇文章和 8 本电子书分享了我的专业知识。凭借十多年的教学经验,我努力使编程变得易于理解且引人入胜。

列表 C 标准库