无符号长整数的确切值范围是多少?

问题描述 投票:4回答:5

我正在完成“以艰难的方式学习C”一书中的练习。练习7要求读者找到使unsigned long的范围超过的值。

long更改为unsigned long并尝试找到使其太大的数字。

所以我的方法是首先在我的机器上获得unsigned long的大小:

printf("SIZEOF ULONG: %lu", sizeof(unsigned long));

这会打印出8。所以假设unsigned long在我的机器上占用了64位,我查找了Wikipedia的最大范围。

64位(字,双字,长字,长字,四字,四字,qword,int64)

  • 无符号:从0到18,446,744,073,709,551,615

我期待声明具有上述值的unsigned long将在没有警告的情况下编译,直到我将值增加1.但结果是不同的。编译以下程序会导致警告。

#include <stdio.h>
int main()
{
    unsigned long value = 18446744073709551615;
    printf("SIZEOF ULONG: %lu", sizeof(unsigned long));
    printf("VALUE: %lu", value);
    return 0;
}

bla.c: In function ‘main’:
bla.c:5:27: warning: integer constant is so large that it is unsigned
     unsigned long value = 18446744073709551615;
                           ^~~~~~~~~~~~~~~~~~~~

那么为什么gcc抱怨价值变大,我以为我已经宣布它为unsigned

c long-integer unsigned
5个回答
5
投票

如果十进制整数常量适合该范围,则它们的类型为int,否则它们的类型为longlong long。它们没有无符号类型,如果值超出了那些有符号范围,则会收到警告。您需要为常量添加ul后缀以使其具有正确的类型。

在不知道其大小的情况下,还可以更轻松地获得此类型的最大值。只需将-1转换为此类型。

unsigned long value = (unsigned long)-1;

3
投票

对于值的整数文字,你需要一个后缀,而不是long int(或者long long int,因为C99和C ++ 11)。以下任何一项都符合unsigned long int:

unsigned long value = 18446744073709551615u;
unsigned long value = 18446744073709551615lu;
unsigned long value = 18446744073709551615ul;

请在此处查看后缀表:

https://en.cppreference.com/w/c/language/integer_constant(对于C)https://en.cppreference.com/w/cpp/language/integer_literal(对于C ++)


1
投票

编译器分几步处理unsigned long value = 18446744073709551615;。在用值初始化value之前,它必须从源代码中读取18446744073709551615并解释它。

源代码中的数字18446744073709551615独立存在 - 它不会立即受到这样一个事实的影响:在一瞬间,它将用于初始化value。它根据C标准中的规则进行处理。

这些规则说带有十进制数字且没有后缀的数字是intlong intlong long int,无论哪个是第一个可以代表该值的数字。由于18446744073709551615是如此之大,它不适合任何这些类型。

编译器警告您,由于18446744073709551615不适合任何这些类型,因此它使用无符号类型。在其他情况下,这可能会改变代码的含义。但是,在这种情况下,由于该值立即用于初始化unsigned long,因此它将具有所需的效果。

要解决此问题,您可以添加u后缀,将其更改为18446744073709551615u。对于以u为后缀的十进制数字,C标准表示该类型是可以表示该值的unsigned intunsigned long intunsigned long long int中的第一个。

(C标准继续说,如果一个值对于列出的类型来说太大,C实现可以用扩展的整数类型表示它或者它没有类型。没有类型的后果可能是有趣的探索,但这是语言律师问题的主题。)


0
投票

使用unsigned long value = 18446744073709551615ul;其他18446744073709551615ul读作int而不是long

如果你想知道无符号长整数和最大值的位数:

#include <stdio.h>
#include <limits.h>

int main()
{
    printf("number of bits in ULONG: %d\nULONG_MAX = %lu\n",
       sizeof(unsigned long) * CHAR_BIT,
       ULONG_MAX);
    return 0;
}

编译和执行:

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra u.c
pi@raspberrypi:/tmp $ ./a.out
number of bits in ULONG: 32
ULONG_MAX = 4294967295

是的,我的长期不在64位


0
投票

整数常数18446744073709551615太大,无法在系统上表示为intlong intlong long int。编译器警告你它使它成为unsigned long long的事实。

让我们尝试编译这个程序:

#include <stdio.h>

int main() {
    if (-1 < 18446744073709551615)
        printf("TRUE\n");
    else
        printf("FALSE\n");

    return 0;
}

gcc确实发出警告:

#1 with x86-64 gcc 8.2
<source>: In function 'main':
<source>:7:14: warning: integer constant is so large that it is unsigned
     if (-1 < 18446744073709551615)
              ^~~~~~~~~~~~~~~~~~~~

程序输出是这样的:

TRUE

clang生成更明确的警告:

#1 with x86-64 clang 7.0.0
<source>:7:14: warning: integer literal is too large to be represented in a signed integer type, interpreting as unsigned [-Wimplicitly-unsigned-literal]
    if (-1 < 18446744073709551615)
             ^

但程序输出是:

FALSE

如果18446744073709551615确实被解释为无符号,就像写成18446744073709551615u0xffffffffffffffff一样,必须使用无符号算术进行比较并且失败,因为两个数字具有相同的值。 clang做它所说的,但gcc没有。

在您的情况下,将值存储到unsigned long变量应该产生预期的结果,但是向常量添加u后缀将确保编译器使用正确的类型对其进行解析。

但请注意,您可以通过将-1强制转换为该类型来获取任何无符号类型的最大值。您还可以使用<limits.h>中定义的宏:类型unsigned long的最大值是ULONG_MAX

© www.soinside.com 2019 - 2024. All rights reserved.