unsigned long的确切值范围是多少?

时间:2019-02-21 18:32:57

标签: c long-integer unsigned

我正在研究“努力学习C”一书中的练习。练习7要求读者找到使unsigned long的范围超出范围的值。

  

long更改为unsigned long,然后尝试查找太大的数字。

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

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

这将打印8。因此,假设unsigned long在我的计算机上占用了64位,我在Wikipedia上查找了最大范围。

64位(word,doubleword,longword,long long,quad,quadword,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

5 个答案:

答案 0 :(得分:5)

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

还有一种更容易的方法来获取此类型的最大值,而无需知道其大小。只需将-1强制转换为这种类型。

unsigned long value = (unsigned long)-1;

答案 1 :(得分:3)

您需要为整数文字添加一个后缀,以获取不适合长整型(或长整型,因为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 ++)

答案 2 :(得分: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实现可以使用扩展的整数类型来表示它,或者它没有类型。没有类型的后果可能是很有意思,但这是语言律师问题的主题。)

答案 3 :(得分:0)

使用unsigned long value = 18446744073709551615ul;否则将18446744073709551615ul读为 int 而不是 long

如果您想知道 unsigned 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位上

答案 4 :(得分: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