C编译器无法识别无符号长

C编译器无法识别无符号长,c,long-integer,implicit-conversion,unsigned,unsigned-integer,C,Long Integer,Implicit Conversion,Unsigned,Unsigned Integer,在我的计算机上,long的最大值为9223372036854775807。但是,当我使用更大的值来解释无符号长时,编译器会抛出一条警告,说它需要被解释为无符号长,而我已经将它定义为无符号长。为什么会这样 //assigning maximum value of a long integer. (No error) long max_l = 9223372036854775807L; //assigning an unsigned long integer. unsigned long max_

在我的计算机上,
long
的最大值为
9223372036854775807
。但是,当我使用更大的值来解释
无符号长
时,编译器会抛出一条警告,说它需要被解释为
无符号长
,而我已经将它定义为无符号长。为什么会这样

//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]

此整数常量:

9223372036854775808L
太大,无法存储在
long

相反,请使用:

9223372036854775808UL
通过添加后缀
UL

或者只使用后缀
U

unsigned long max_ul = 9223372036854775808U;
当整数常量的后缀为
L
(或
L
)时,编译器将按以下顺序确定其类型:第一种类型

signed long
signed long long
其中可以表示其值。类型
signed long
似乎与编译器建立的类型
signed long
具有相同的整数表示形式。因此,类型
signed long
和类型
signed long
都不能表示常量。对于这些类型,常量太大。但是与编译器建立的类型
unsigned 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;
}

表达式
-1[p]
与表达式
-1[p]
不同。它被处理为
-(1[p])
,相当于
-p[1]
每个整数常量,如
9223372036854775808
都有自己的类型。对于编译器在程序中为整型常量选择什么类型,有一些规则。对于纯十进制常量(不带任何U,L后缀),它如下所示:

  • 如果它适合内部
    int
    ,请尝试
  • 如果没有,请尝试是否适合
    long
  • 如果没有,请尝试是否适合
    long
(详见C17 6.4.4.1中的表格)

显然,所有这些检查在系统上的值2^63都失败了,这是意料之中的,因为有符号的64位只能上升到2^63-1

添加
L
不会解决任何问题,因为这只会告诉编译器执行上述检查,而从
long
开始

将存储整型常量的类型声明为无符号不会解决任何问题,因为赋值/初始化左侧的类型与整型常量的类型无关。您可以编写
my_custom_type x=9223372036854775808L和您将得到相同的警告


显而易见的解决方案是使用无符号后缀
U
。否则,如果出于某种原因需要大于63位的有符号位,则需要找到一些128位的有符号“大整数”库,这将非常痛苦。

是的。这很有效。还请注意,
%lu
需要用作格式设置程序来打印正确的数字。您可以删除前缀。请注意,假设系统具有64位
且没有更大的扩展整数类型,则此代码在C90中的行为与在更高版本中不同。在C90中,即使后缀是
L
,常数的类型也将是
无符号长
,而自C99以来,没有
u
的十进制常数只能有符号类型(如果没有合适的类型,则会违反约束)。因此,它与调用编译器的模式有关。
#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