ZetCode

C strtoull 函数

最后修改:2025 年 4 月 8 日

字符串到数字的转换是 C 编程中一项常见的任务,而 `strtoull` 提供了一种可靠的方法将字符串转换为无符号长长整型。本教程将深入介绍 `strtoull`,包括其语法、用法和错误处理。我们将探讨实际示例,并讨论为什么它比 `atoll` 等替代方法更安全。理解 `strtoull` 有助于创建更可靠且能正确处理数字输入的程序。

什么是 strtoull?

`strtoull` 函数将字符串转换为无符号长长整型。它声明在 `stdlib.h` 中,并提供强大的错误处理功能。与 `atoll` 不同,它可以检测转换错误并支持不同的数字基数。该函数接受三个参数:输入字符串、可选的结束指针和数字基数(0 到 36)。它返回转换后的值,在出错时返回 0,并将 `errno` 设置为指示特定问题。

strtoull 的基本用法

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

basic_conversion.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main() {
    const char *num_str = "18446744073709551615";
    char *endptr;
    unsigned long long num;

    errno = 0;
    num = strtoull(num_str, &endptr, 10);

    if (errno == ERANGE) {
        printf("Number out of range\n");
        return 1;
    } else if (*endptr != '\0') {
        printf("Invalid characters in input\n");
        return 1;
    }

    printf("Converted number: %llu\n", num);
    return 0;
}

在这里,`strtoull` 将 64 位无符号最大值从字符串中转换出来。我们检查 `errno` 是否有范围错误,并检查 `endptr` 是否包含无效字符。基数 10 指定十进制转换。这种方法比 `atoll` 安全得多,`atoll` 不提供错误检测。在使用转换结果之前,请务必验证它。

十六进制转换

`strtoull` 在指定基数 16 时可以转换十六进制字符串。

hex_conversion.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main() {
    const char *hex_str = "0xFFFFFFFFFFFFFFFF";
    char *endptr;
    unsigned long long num;

    errno = 0;
    num = strtoull(hex_str, &endptr, 16);

    if (errno == ERANGE) {
        printf("Number out of range\n");
        return 1;
    } else if (*endptr != '\0' && *endptr != '\n') {
        printf("Invalid characters in input\n");
        return 1;
    }

    printf("Hexadecimal %s = %llu in decimal\n", hex_str, num);
    return 0;
}

此示例将十六进制字符串转换为无符号长长整型。基数 16 参数启用十六进制转换,“0x”前缀是允许的,但不是必需的。我们检查 `errno` 和 `endptr` 是否存在错误。请注意,十六进制字母可以是大小写。该函数在尝试转换之前会跳过前导空格。

自动基数检测

当指定基数 0 时,`strtoull` 会自动检测数字基数。

auto_base.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main() {
    const char *inputs[] = {"42", "052", "0x2A", NULL};
    char *endptr;
    unsigned long long num;

    for (int i = 0; inputs[i] != NULL; i++) {
        errno = 0;
        num = strtoull(inputs[i], &endptr, 0);

        if (errno == ERANGE) {
            printf("%s: Number out of range\n", inputs[i]);
            continue;
        } else if (*endptr != '\0') {
            printf("%s: Invalid characters\n", inputs[i]);
            continue;
        }

        printf("%s = %llu (auto-detected base)\n", inputs[i], num);
    }

    return 0;
}

使用基数 0 时,`strtoull` 会像标准的 C 常量一样解释数字:默认情况下为十进制,以 0 为前缀时为八进制,以 0x 为前缀时为十六进制。此示例自动转换十进制、八进制和十六进制字符串。当输入格式事先未知时,该函数提供了灵活性。使用自动基数检测时,请务必验证转换结果。

使用 strtoull 进行错误处理

此示例演示了使用 `strtoull` 进行全面的错误处理。

error_handling.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>

int main() {
    const char *test_cases[] = {
        "12345678901234567890",  // Valid
        "99999999999999999999",  // Too large
        "12abc",                 // Partial conversion
        "   -123",               // Negative (allowed but clamped)
        NULL
    };
    char *endptr;

    for (int i = 0; test_cases[i] != NULL; i++) {
        errno = 0;
        unsigned long long num = strtoull(test_cases[i], &endptr, 10);

        printf("Input: \"%s\"\n", test_cases[i]);
        printf("Converted: %llu\n", num);

        if (errno == ERANGE) {
            printf("Error: Number out of range (ERANGE)\n");
        }
        if (*endptr != '\0') {
            printf("Warning: Stopped at invalid character '%c'\n", *endptr);
        }
        if (test_cases[i] == endptr) {
            printf("Error: No conversion performed\n");
        }
        printf("\n");
    }

    return 0;
}

此示例展示了使用 `strtoull` 的各种错误情况。我们测试有效数字、溢出、部分转换和负值。技术上允许负数,但会转换为其无符号等效值。`endptr` 有助于识别转换停止的位置。多重检查为健壮的输入处理提供了完整的错误检测。

使用不同基数的 strtoull

`strtoull` 支持从 2 到 36 的基数转换。

multi_base.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main() {
    const char *binary = "101010";
    const char *ternary = "2101";
    const char *base36 = "z3kq";
    char *endptr;
    unsigned long long num;

    // Binary conversion (base 2)
    num = strtoull(binary, &endptr, 2);
    printf("Binary %s = %llu\n", binary, num);

    // Ternary conversion (base 3)
    num = strtoull(ternary, &endptr, 3);
    printf("Ternary %s = %llu\n", ternary, num);

    // Base36 conversion (digits 0-9, letters a-z)
    num = strtoull(base36, &endptr, 36);
    printf("Base36 %s = %llu\n", base36, num);

    return 0;
}

此示例演示了使用不同数字基数的 `strtoull`。基数 2 转换二进制字符串,基数 3 处理三进制,基数 36 支持字母数字(0-9,a-z)。字母可以是大小写。该函数为解析各种格式的数字提供了极大的灵活性。请记住,大于 10 的基数使用字母作为附加数字(a=10,b=11,依此类推)。

使用 strtoull 的最佳实践

来源

C strtoull 文档

本教程探讨了 `strtoull` 函数,从基本用法到高级错误处理。正确的字符串到数字转换对于安全可靠的 C 程序至关重要。在处理数字转换时,请始终验证输入并处理潜在的错误。

作者

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

列表 C 标准库