C 编译器无法识别 unsigned long
C compiler not recognizing unsigned long
在我的电脑上,long
取最大值 9223372036854775807
。但是,当我用更大的值厌倦 unsigned long
时,编译器会发出警告,说它需要被解释为 unsigned long
,而我已经将它定义为 unsigned long
。为什么会这样?
//assigning maximum value of a long integer. (No error)
long max_l = 9223372036854775807L;
//assigning an unsigned long integer.
unsigned long max_ul = 9223372036854775808L; //warning: integer literal is too large to be represented in a signed
//integer type, interpreting as unsigned [-Wimplicitly-unsigned-literal]
cc --version
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
这个整数常量:
9223372036854775808L
太大,无法存储在 long
中。
改为使用:
9223372036854775808UL
这通过附加后缀 UL
来指定常量具有类型 unsigned long
或者直接使用后缀U
:
unsigned long max_ul = 9223372036854775808U;
当整数常量具有后缀 L
(或 l
)时,编译器将按以下顺序确定其类型:第一个类型
signed long
signed long long
其中可以体现它的价值。似乎 signed long
类型与编译器建立的 signed long long
类型具有相同的整数表示形式。所以类型 signed long
和类型 signed long long
都不能表示常量。对于这些类型,常量太大。但是与编译器建立的类型unsigned long long
具有相同内部表示的类型unsigned long
可以表示常量
还要注意C中没有负整数常量。
例如,如果您将写
int x = -1;
然后编译器将构造 -1
拆分为两个标记:整数常量 1
和一元运算符 -
.
考虑以下演示程序
#include <stdio.h>
int main(void)
{
int a[] = { 0, 1, 2 };
int *p = a + 1;
printf( "p[-1] = %d\n", p[-1] );
printf( "-1[p] = %d\n", -1[p] );
return 0;
}
程序输出为
p[-1] = 0
-1[p] = -2
表达式 -1[p]
与表达式 (-1)[p]
不同。它被处理为 -(1[p] )
相当于 -p[1]
.
每个整型常量(例如 9223372036854775808
)都有自己的类型。对于编译器在程序中为整数常量选择什么类型有一些规则。对于普通十进制常量(没有任何 U、L 后缀),它是这样的:
- 试试它是否适合
int
。
- 如果不是,请尝试它是否适合
long
。
- 如果不是,请尝试它是否适合
long long
。
(详见C17 6.4.4.1中的table)
显然,对于您系统上的值 2^63,所有这些检查都失败了,这是预料之中的,因为带符号的 64 位只能达到 2^63 - 1。
添加 L
并不能解决任何问题,因为这只会告诉编译器进行上述检查但从 long
.
开始
将整数常量的存储类型声明为无符号并不能解决任何问题,因为 assignment/initialization 左侧的类型与整数常量的类型无关。你可以写 my_custom_type x = 9223372036854775808L;
并且你会得到同样的警告。
显而易见的解决方案是使用无符号后缀 U
。否则,如果您出于某种原因需要 >63 位签名的值,则需要找到一些 128 位签名的 "big int" 库,这会更加痛苦。
在我的电脑上,long
取最大值 9223372036854775807
。但是,当我用更大的值厌倦 unsigned long
时,编译器会发出警告,说它需要被解释为 unsigned long
,而我已经将它定义为 unsigned long
。为什么会这样?
//assigning maximum value of a long integer. (No error)
long max_l = 9223372036854775807L;
//assigning an unsigned long integer.
unsigned long max_ul = 9223372036854775808L; //warning: integer literal is too large to be represented in a signed
//integer type, interpreting as unsigned [-Wimplicitly-unsigned-literal]
cc --version
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
这个整数常量:
9223372036854775808L
太大,无法存储在 long
中。
改为使用:
9223372036854775808UL
这通过附加后缀 UL
unsigned long
或者直接使用后缀U
:
unsigned long max_ul = 9223372036854775808U;
当整数常量具有后缀 L
(或 l
)时,编译器将按以下顺序确定其类型:第一个类型
signed long
signed long long
其中可以体现它的价值。似乎 signed long
类型与编译器建立的 signed long long
类型具有相同的整数表示形式。所以类型 signed long
和类型 signed long long
都不能表示常量。对于这些类型,常量太大。但是与编译器建立的类型unsigned long long
具有相同内部表示的类型unsigned long
可以表示常量
还要注意C中没有负整数常量。 例如,如果您将写
int x = -1;
然后编译器将构造 -1
拆分为两个标记:整数常量 1
和一元运算符 -
.
考虑以下演示程序
#include <stdio.h>
int main(void)
{
int a[] = { 0, 1, 2 };
int *p = a + 1;
printf( "p[-1] = %d\n", p[-1] );
printf( "-1[p] = %d\n", -1[p] );
return 0;
}
程序输出为
p[-1] = 0
-1[p] = -2
表达式 -1[p]
与表达式 (-1)[p]
不同。它被处理为 -(1[p] )
相当于 -p[1]
.
每个整型常量(例如 9223372036854775808
)都有自己的类型。对于编译器在程序中为整数常量选择什么类型有一些规则。对于普通十进制常量(没有任何 U、L 后缀),它是这样的:
- 试试它是否适合
int
。 - 如果不是,请尝试它是否适合
long
。 - 如果不是,请尝试它是否适合
long long
。
(详见C17 6.4.4.1中的table)
显然,对于您系统上的值 2^63,所有这些检查都失败了,这是预料之中的,因为带符号的 64 位只能达到 2^63 - 1。
添加 L
并不能解决任何问题,因为这只会告诉编译器进行上述检查但从 long
.
将整数常量的存储类型声明为无符号并不能解决任何问题,因为 assignment/initialization 左侧的类型与整数常量的类型无关。你可以写 my_custom_type x = 9223372036854775808L;
并且你会得到同样的警告。
显而易见的解决方案是使用无符号后缀 U
。否则,如果您出于某种原因需要 >63 位签名的值,则需要找到一些 128 位签名的 "big int" 库,这会更加痛苦。