使用位移位计算C中的有符号长最大值
昨天刚开始学习C,这会让我在元旦疯狂。。。尝试使用位移位操作打印不同的整数范围。除了签名的长最大/最小值外,其他一切正常。无法理解为什么使用位移位计算C中的有符号长最大值,c,bit-shift,C,Bit Shift,昨天刚开始学习C,这会让我在元旦疯狂。。。尝试使用位移位操作打印不同的整数范围。除了签名的长最大/最小值外,其他一切正常。无法理解为什么(1请记住,编程语言是一种规范,在某些技术报告中用英语编写。它不是软件。有关详细信息,请参阅 像1这样的文字常量不是long,而是int 要对文字常量long1进行编码,您需要编写1L(或者您可以编写(long)1…)。要对文字常量无符号long1进行编码,您应该编写1all(或code(无符号long)1,这是一个常量表达式 文字常量适合足够大的“最小”整数类
(1请记住,编程语言是一种规范,在某些技术报告中用英语编写。它不是软件。有关详细信息,请参阅
像1
这样的文字常量不是long
,而是int
要对文字常量long
1进行编码,您需要编写1L
(或者您可以编写(long)1
…)。要对文字常量无符号long
1进行编码,您应该编写1all
(或code(无符号long)1
,这是一个常量表达式
文字常量适合足够大的“最小”整数类型。因此1
是int
,在64位计算机上(实际上,是像我的Linux/x86-64那样的C实现)1000000000
(即1010)是长的(因为它不适合int
),因为在这样的计算机上,int
-s有32位,long
-s有64位
请注意,int
的大小或范围不是由C99或C11标准精确定义的,并且可能因实现的不同而有所不同。您可能希望包括和使用类型,如int32\t
因此1表达式计算为int
,因为两个操作数都是int
s。您需要将它们设置为long
s:
((1LL << 63) - 1)
(((long long)1 << 63) -1)
((1LL您的代码多次调用未定义的行为:
- 左移位
1
,一个int
值,移位量大于类型中的位数减1,调用未定义的行为
- 将有符号整数左移任意量,使结果值超出类型的范围将调用未定义的行为,就像所有其他有符号算术溢出一样
用移位计算这些最大值是不方便的。如果您可以假设2s个补码而不使用填充位,则可以使用按位补码来获得最大无符号值,并将其向右移位一次以获得最大有符号值,然后对其求反并减去一以获得最小有符号值
以下是更正后的代码:
#include <limits.h>
#include <stdio.h>
int main(void) {
// char
unsigned char ucmin = 0;
unsigned char ucmax = ~ucmin;
signed char scmax = ucmax >> 1;
signed char scmin = -scmax - 1;
char cmax = ((char)(-1)) < 0 ? scmax : ucmax;
char cmin = ((char)(-1)) < 0 ? scmin : ucmin;
printf("signed char min: %d = %d, signed char max: %d = %d\n",
scmin, SCHAR_MIN, scmax, SCHAR_MAX);
printf("unsigned char min: %d, unsigned char max: %u = %u\n",
ucmin, ucmax, UCHAR_MAX);
printf("char min: %d = %d, char max: %d = %d\n",
cmin, CHAR_MIN, cmax, CHAR_MAX);
// short
unsigned short usmin = 0;
unsigned short usmax = ~usmin;
signed short smax = usmax >> 1;
signed short smin = -smax - 1;
printf("short min: %d = %d, short max: %d = %d\n",
smin, SHRT_MIN, smax, SHRT_MAX);
printf("unsigned short min: %d, unsigned sort max: %u = %u\n",
usmin, usmax, USHRT_MAX);
// int
unsigned int umin = 0;
unsigned int umax = ~umin;
signed int imax = umax >> 1;
signed int imin = -imax - 1;
printf("int min: %d = %d, int max: %d = %d\n",
imin, INT_MIN, imax, INT_MAX);
printf("unsigned int min: %u, unsigned int max: %u = %u\n",
umin, umax, UINT_MAX);
// long int
unsigned long ulmin = 0;
unsigned long ulmax = ~ulmin;
signed long lmax = ulmax >> 1;
signed long lmin = -lmax - 1;
printf("long int min: %ld = %ld, long int max: %ld = %ld\n",
lmin, LONG_MIN, lmax, LONG_MAX);
printf("unsigned long int min: %lu, unsigned long int max: %lu = %lu\n",
ulmin, ulmax, ULONG_MAX);
// long long int
unsigned long long ullmin = 0;
unsigned long long ullmax = ~ullmin;
signed long long llmax = ullmax >> 1;
signed long long llmin = -llmax - 1;
printf("long long int min: %lld = %lld, long long int max: %lld = %lld\n",
llmin, LLONG_MIN, llmax, LLONG_MAX);
printf("unsigned long long int min: %llu, unsigned long long int max: %llu = %llu\n",
ullmin, ullmax, ULLONG_MAX);
return 0;
}
#包括
#包括
内部主(空){
//煤焦
无符号字符ucmin=0;
无符号字符ucmax=~ucmin;
有符号字符scmax=ucmax>>1;
有符号字符scmin=-scmax-1;
字符cmax=((字符)(-1))<0?scmax:ucmax;
char cmin=((char)(-1))<0?scmin:ucmin;
printf(“签名字符最小值:%d=%d,签名字符最大值:%d=%d\n”,
scmin、SCHAR_MIN、scmax、SCHAR_MAX);
printf(“未签名字符最小值:%d,未签名字符最大值:%u=%u\n”,
ucmin、ucmax、UCHAR_MAX);
printf(“字符最小值:%d=%d,字符最大值:%d=%d\n”,
cmin、CHAR_MIN、cmax、CHAR_MAX);
//短
无符号短usmin=0;
无符号短usmax=~usmin;
有符号短smax=usmax>>1;
符号短smin=-smax-1;
printf(“短最小值:%d=%d,短最大值:%d=%d\n”,
smin、SHRT_最小值、smax、SHRT_最大值);
printf(“无符号短最小值:%d,无符号排序最大值:%u=%u\n”,
usmin、usmax、USHRT_MAX);
//int
无符号整数umin=0;
无符号int-umax=~umin;
签名的int-imax=umax>>1;
有符号整数imin=-imax-1;
printf(“最小整数:%d=%d,最大整数:%d=%d\n”,
imin、INT_MIN、imax、INT_MAX);
printf(“未签名整数最小值:%u,未签名整数最大值:%u=%u\n”,
umin、umax、UINT_MAX);
//长整型
无符号长ulmin=0;
无符号长ulmax=~ulmin;
有符号长lmax=ulmax>>1;
有符号长lmin=-lmax-1;
printf(“长整数最小值:%ld=%ld,长整数最大值:%ld=%ld\n”,
lmin、LONG_MIN、lmax、LONG_MAX);
printf(“无符号长整数最小值:%lu,无符号长整数最大值:%lu=%lu\n”,
ulmin、ulmax、ULONG_MAX);
//长整型
无符号长ullmin=0;
无符号长ullmax=~ullmin;
有符号长llmax=ullmax>>1;
有符号长llmin=-llmax-1;
printf(“长整型最小值:%lld=%lld,长整型最大值:%lld=%lld\n”,
llmin,LLONG_MIN,llmax,LLONG_MAX);
printf(“无符号长整型最小值:%llu,无符号长整型最大值:%llu=%llu\n”,
ullmin、ullmax、ULLONG_MAX);
返回0;
}
此行:
long long lmax = (1 << 63) - 1L; // WHY DOES THIS NOT WORK???
类似地,对于您遇到问题的另一个表达式
编译器没有告诉您这个问题,这意味着您的编译没有启用警告
对于gcc
,至少应使用:
-Wall -Wextra -pedantic
我还发现这些参数非常有用:
-Wconversion -std=gnu99
(1LL不必检查代码,也许你应该尝试用十六进制打印。你可以使用%x
和%llx
。你应该得到0x7FFFFFFF
long-long-lmax=(1long-long-lmax=(1如果int
的长度不超过64位,则1将int
常量强制转换为long
不是一个好主意。这就是后缀的作用。但是OP似乎需要固定宽度的类型,所以UINT64\u C(1)
将是正确的形式。另外,long
在64位体系结构上不保证为64位,这是ABI的问题,请参阅Windows,即IL32LLP64。为什么unsigned long ulmax=(1顺便说一句,谢谢关于字符可以是有符号的或无符号的部分;我知道这一点,我正在使用Microsoft C/C++编译器,它将字符视为有符号的。为什么无符号长ulmax=(1)您的意思是当-1LL
转换为无符号时,它会导致max无符号长
,因为max-long-long与max-unsigned-long-long不一样。超级!这非常有用!还有一个问题,为什么
warning: integer overflow in exression [-Woverflow]
-Wall -Wextra -pedantic
-Wconversion -std=gnu99
((1LL << 62) - 1) | (1LL << 62)