C语言中如何确定无符号长整型的范围?

How can I confirm the range of unsigned long integer in C?

unsigned long 在我的 Linux gcc 上有 8 个字节。

unsigned long long 在我的 Linux gcc 上也有 8 个字节。

所以我认为他们可以显示的整数范围是从 0 min(2^64 - 1)max.

现在我想确认一下我是不是正确的。

这是我的代码:

#include <stdio.h>
int main(void)
{
    printf("long takes up %d bytes:\n", sizeof(long));
    printf("long long takes up %d bytes:\n", sizeof(long long));

    unsigned long a = 18446744073709551615;
    a++;
    printf("a + 1 = %lu\n", a); 

    unsigned long long b = 18446744073709551615;
    b++;
    printf("b + 1 = %llu\n", b); 

    return 0;
}

但是,代码无法编译,我收到以下警告:

warning: integer constant is so large that it is unsigned

我哪里做错了?我该如何修改代码?

用-1初始化无符号数。这将自动成为 C 中的最大值。

#include <stdio.h>
int main(void)
{
    printf("long takes up %d bytes:\n", sizeof(long));
    printf("long long takes up %d bytes:\n", sizeof(long long));

    unsigned long a = -1;
    printf("a = %lu\n", a); 

    unsigned long long b = -1;
    printf("b = %llu\n", b); 

    return 0;
}

更新:根据评论更改了代码:)

您在 <limits.h> 中找到了一些有用的定义。

初始化num时,可以为unsigned long追加"UL",为[=追加ULL 12=]。

例如:

unsigned long a = 18446744073709551615UL;
unsigned long long b = 18446744073709551615ULL;

此外,使用 %zu 而不是 %d 因为 sizeof return size_t.

根据cppreference

  • integer-suffix, if provided, may contain one or both of the following (if both are provided, they may appear in any order:
    • unsigned-suffix (the character u or the character U)
    • long-suffix (the character l or the character L) or the long-long-suffix (the character sequence ll or the character sequence LL) (since C99)

C standard 5.2.4.2.1 整数类型的大小 <limits.h> :

1 The values given below shall be replaced by constant expressions suitable for use in #if preprocessing directives. Moreover, except for CHAR_BIT and MB_LEN_MAX, the following shall be replaced by expressions that have the same type as would an expression that is an object of the corresponding type converted according to the integer promotions. Their implementation-defined values shall be equal or greater in magnitude (absolute value) to those shown, with the same sign.

如 rsp 所述,您可以使用 ULULL 指定文字的类型。 但这不会在您的算术代码中得出结论性的结果。

您打印的价值将始终是 0 因为

2^64 % 64 = 0 // 64 = 8 byte
2^64 % 32 = 0 // 32 = 4 byte
2^64 % 16 = 0 // 16 = 2 byte

如您所见,变量大小总是加倍,因此,如果您使用 8 字节的包装数字,它只是将多种类型包装在较小的尺寸上,并产生相同的结果。

sizeof 会显示正确的值。

但通常您希望在代码中而不是在输出中检查这些内容,因此您可以按照 Arndt Jonasson 的建议使用 limits.h

或者你可以使用static_assert在编译时检查。

How can I confirm the range of unsigned long integer in C?

最佳,只需使用 <limits.h> 中的宏即可。它更好地自我记录代码的意图。

unsigned long long b_max = ULLONG_MAX;

或者,将 -1 分配给 unsigned 类型。由于 -1 不在 unsigned 类型的范围内,它将通过将该类型的 MAX 值加 1 来转换为目标类型。即使在具有填充。

... if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type. C11dr §6.3.1.3 2

对于 unsigned 类型,最小值当然是 0。

unsigned long long b_min = 0;
unsigned long long b_max = -1;
printf("unsigned long long range [%llu %llu]\n", b_min, b_max); 

请注意,挑剔的编译器会抱怨使用 b_max = -1; 分配超出范围的值。使用 ULLONG_MAX


Where did I do wrong?

警告 "warning: integer constant is so large that it is unsigned" 是由于 18446744073709551615 是您平台上 long long 范围之外的整数十进制常量。朴素的十进制常量仅限于此。追加 Uu。那么编译器会考虑unsigned long long.

unsigned long long b = 18446744073709551615u;

此外,没有 C 规范说 18446744073709551615 是 unsigned long long 的最大值。它必须至少 。它可能更大。所以分配 b = 18446744073709551615u 可能不会分配 max 值。

How can I modify the code ?

如上所示