我正在研究“努力学习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)
我期望声明具有以上值的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
?
答案 0 :(得分:5)
如果十进制整数常数在该范围内,则其类型为int
,否则为long
或long 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标准中的规则进行处理的。
这些规则说带有十进制数字且没有后缀的数字是int
,long int
或long long int
,无论哪个是可以代表该值的第一个。由于18446744073709551615太大,因此不适合任何这些类型。
编译器警告您,由于18446744073709551615不适合任何这些类型,因此它正在使用无符号类型。在其他情况下,这可能会更改代码的含义。但是,在这种情况下,由于该值将立即用于初始化unsigned long
,因此将具有所需的效果。
要解决此问题,您可以添加一个u
后缀,将其更改为18446744073709551615u
。对于后缀为u
的十进制数字,C标准表示类型是可以表示该值的unsigned int
,unsigned long int
或unsigned 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
太大,无法在系统上表示为int
,long int
或long 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
确实被解释为无符号的,就像写为18446744073709551615u
或0xffffffffffffffff
一样,则必须使用无符号算术执行比较,并且比较失败,因为两个数字的值相同。 clang
会说,但gcc
不会。
在您的情况下,将值存储到unsigned long
变量中将产生预期的结果,但是在常量中添加u
后缀将确保编译器使用正确的类型对其进行解析。
但是请注意,可以通过将-1
强制转换为该类型来获得任何无符号类型的最大值。您还可以使用在<limits.h>
中定义的宏:类型unsigned long
的最大值为ULONG_MAX
。