c和c++各种类型数据左移溢出对比
溢出原理参考:C语言的整型溢出问题 | 酷 壳 - CoolShell
c完整测试代码:
1 #include<stdio.h> 2 main(){ 3 //int 4 printf("int:\n"); 5 int j=1; //<<31==2147483648 6 // 1<<32==1 7 // (1<<32)-1==0 8 // (1<<32)-2==4294967295 9 for(int i=30;i<(1<<5)+1;i++) 10 printf("1<<%d==%d\n",i,j<<i); 11 printf("(1<<%d)-1==%d\n",31,(j<<31)-1); 12 printf("(1<<%d)-1==%d\n",32,(j<<32)-1); 13 printf("(1<<%d)-2==%d\n",32,(j<<32)-2); 14 // unsigned int 15 printf("\nunsigned int:\n"); 16 unsigned int j2=1;//1<<30==1073741824 17 // 1<<31==2147483648 18 // 1<<32==1 19 // (1<<31)-1==2147483647 20 // (1<<32)-1==0 21 // (1<<32)-2==4294967295 22 for(int i=30;i<(1<<5)+1;i++) 23 printf("1<<%d==%u\n",i,j2<<i); 24 printf("(1<<%d)-1==%u\n",31,(j2<<31)-1); 25 printf("(1<<%d)-1==%u\n",32,(j2<<32)-1); 26 printf("(1<<%d)-2==%u\n",32,(j2<<32)-2); 27 //long 28 printf("\nlong:\n"); 29 long j3=1;//1<<63==-9223372036854775808 30 // 1<<64==1 31 // (1<<63)-1==9223372036854775807 32 // (1<<64)-1==0 33 // (1<<64)-2==-1 34 for(int i=62;i<(1<<6)+1;i++) 35 printf("1<<%d==%ld\n",i,j3<<i); 36 printf("(1<<%d)-1==%ld\n",63,(j3<<63)-1); 37 printf("(1<<%d)-1==%ld\n",64,(j3<<64)-1); 38 printf("(1<<%d)-2==%ld\n",64,(j3<<64)-2); 39 // unsigned long 40 printf("\nunsigned long:\n"); 41 unsigned long j4=1; //1<<62==4611686018427387904 42 // 1<<63==9223372036854775808 43 // 1<<64==1 44 // (1<<63)-1==9223372036854775807 45 // (1<<64)-1==0 46 // (1<<64)-2==18446744073709551615 47 for(int i=62;i<(1<<6)+1;i++) 48 printf("1<<%d==%lu\n",i,j4<<i); 49 printf("(1<<%d)-1==%lu\n",63,(j4<<63)-1); 50 printf("(1<<%d)-1==%lu\n",64,(j4<<64)-1); 51 printf("(1<<%d)-2==%lu\n",64,(j4<<64)-2); 52 }
运行结果:
int:
1<<30==1073741824
1<<31==-2147483648
1<<32==1
(1<<31)-1==2147483647
(1<<32)-1==0
(1<<32)-2==-1
unsigned int:
1<<30==1073741824
1<<31==2147483648
1<<32==1
(1<<31)-1==2147483647
(1<<32)-1==0
(1<<32)-2==4294967295
long:
1<<62==4611686018427387904
1<<63==-9223372036854775808
1<<64==1
(1<<63)-1==9223372036854775807
(1<<64)-1==0
(1<<64)-2==-1
unsigned long:
1<<62==4611686018427387904
1<<63==9223372036854775808
1<<64==1
(1<<63)-1==9223372036854775807
(1<<64)-1==0
(1<<64)-2==18446744073709551615
--------------------------------------------------------------
c++如果输出用printf则所有结果与c相同。
下面是用std::cout<<;的输出方式的测试中与printf不同的地方(全是我错误使用格式字符引起的)
c++ int:
(1<<32)-2==
printf():4294967295
std::cout<<::-1
std::cout<<:18446744073709551615
c++完整测试代码:
1 #include<iostream> 2 main(){ 3 //int 4 printf("int:\n"); 5 int j=1; //<<31==2147483648 6 // 1<<32==1 7 // (1<<31)-1==2147483647 8 // (1<<32)-1==0 9 // (1<<32)-2==4294967295 -1 10 for(int i=30;i<(1<<5)+1;i++){ 11 printf("1<<%d==%ld\n",i,j<<i); 12 std::cout<<"1<<"<<i<<"=="<<(j<<i)<<"\n";} 13 std::cout<<"(1<<31)-1"<<"=="<<(j<<31)-1<<"\n"; 14 std::cout<<"(1<<32)-1"<<"=="<<(j<<32)-1<<"\n"; 15 std::cout<<"(1<<32)-2"<<"=="<<(j<<32)-2<<"\n"; 16 printf("(1<<%d)-1==%ld\n",31,(j<<31)-1); 17 printf("(1<<%d)-1==%ld\n",32,(j<<32)-1); 18 printf("(1<<%d)-2==%ld\n",32,(j<<32)-2); 19 // unsigned int 20 printf("\nunsigned int:\n"); 21 unsigned int j2=1;//1<<31==2147483648 22 // 1<<32==1 23 // (1<<32)-1==0 24 // (1<<32)-2==4294967295 25 for(int i=30;i<(1<<5)+1;i++){ 26 printf("1<<%d==%ld\n",i,j2<<i); 27 std::cout<<"1<<"<<i<<"=="<<(j2<<i)<<"\n";} 28 std::cout<<"(1<<31)-1"<<"=="<<(j2<<31)-1<<"\n"; 29 std::cout<<"(1<<32)-1"<<"=="<<(j2<<32)-1<<"\n"; 30 std::cout<<"(1<<32)-2"<<"=="<<(j2<<32)-2<<"\n"; 31 printf("(1<<%d)-1==%ld\n",31,(j2<<31)-1); 32 printf("(1<<%d)-1==%ld\n",32,(j2<<32)-1); 33 printf("(1<<%d)-2==%ld\n",32,(j2<<32)-2); 34 //long 35 printf("\nlong:\n"); 36 long j3=1;//1<<63==-9223372036854775808 37 // 1<<64==1 38 // (1<<63)-1==9223372036854775807 39 // (1<<64)-1==0 40 // (1<<64)-2==-1 41 for(int i=62;i<(1<<6)+1;i++){ 42 printf("1<<%d==%ld\n",i,j3<<i); 43 std::cout<<"1<<"<<i<<"=="<<(j3<<i)<<"\n";} 44 std::cout<<"(1<<63)-1"<<"=="<<(j3<<63)-1<<"\n"; 45 std::cout<<"(1<<64)-1"<<"=="<<(j3<<64)-1<<"\n"; 46 std::cout<<"(1<<64)-2"<<"=="<<(j3<<64)-2<<"\n"; 47 printf("(1<<%d)-1==%ld\n",63,(j3<<63)-1); 48 printf("(1<<%d)-1==%ld\n",64,(j3<<64)-1); 49 printf("(1<<%d)-2==%ld\n",64,(j3<<64)-2); 50 // unsigned long 51 printf("\nunsigned long:\n"); 52 unsigned long j4=1;//1<<63==-9223372036854775808 53 // 1<<64==1 54 // (1<<63)-1==9223372036854775807 55 // (1<<64)-1==0 56 // (1<<64)-2==-1 ,18446744073709551615 57 for(int i=62;i<(1<<6)+1;i++){ 58 printf("1<<%d==%ld\n",i,j4<<i); 59 std::cout<<"1<<"<<i<<"=="<<(j4<<i)<<"\n";} 60 std::cout<<"(1<<63)-1"<<"=="<<(j4<<63)-1<<"\n"; 61 std::cout<<"(1<<64)-1"<<"=="<<(j4<<64)-1<<"\n"; 62 std::cout<<"(1<<64)-2"<<"=="<<(j4<<64)-2<<"\n"; 63 printf("(1<<%d)-1==%ld\n",63,(j4<<63)-1); 64 printf("(1<<%d)-1==%ld\n",64,(j4<<64)-1); 65 printf("(1<<%d)-2==%ld\n",64,(j4<<64)-2); 66 }
运行结果:
int:
1<<30==1073741824
1<<30==1073741824
1<<31==2147483648
1<<31==-2147483648
1<<32==1
1<<32==1
(1<<31)-1==2147483647
(1<<32)-1==0
(1<<32)-2==-1
(1<<31)-1==2147483647
(1<<32)-1==0
(1<<32)-2==4294967295
unsigned int:
1<<30==1073741824
1<<30==1073741824
1<<31==2147483648
1<<31==2147483648
1<<32==1
1<<32==1
(1<<31)-1==2147483647
(1<<32)-1==0
(1<<32)-2==4294967295
(1<<31)-1==2147483647
(1<<32)-1==0
(1<<32)-2==4294967295
long:
1<<62==4611686018427387904
1<<62==4611686018427387904
1<<63==-9223372036854775808
1<<63==-9223372036854775808
1<<64==1
1<<64==1
(1<<63)-1==9223372036854775807
(1<<64)-1==0
(1<<64)-2==-1
(1<<63)-1==9223372036854775807
(1<<64)-1==0
(1<<64)-2==-1
unsigned long:
1<<62==4611686018427387904
1<<62==4611686018427387904
1<<63==-9223372036854775808
1<<63==9223372036854775808
1<<64==1
1<<64==1
(1<<63)-1==9223372036854775807
(1<<64)-1==0
(1<<64)-2==18446744073709551615
(1<<63)-1==9223372036854775807
(1<<64)-1==0
(1<<64)-2==-1
为什么printf和cout不完全一致:https://tieba.baidu.com/p/8421942192
别人:cout的类型推断一定是正确的,如果printf和cout的结果不同,那说明使用了错误的转换说明
我:刚刚学完signed和unsigned、%d和%D、以及整数和位移溢出。 cout的类型推断一定是正确的,这一点我认同。在cout中它并没有错误地将无符号数当成有符号数或将有符号数当成无符号数输出。 而printf就不一样了,即便我指定了正确的占位符,它有时还是会将有符号是当成无符号数输出,如第7行第1列应该是(1<<32)-2==-1而不是(1<<32)-2==4294967295;第14行第2列应该是(1<<64)-2==18446744073709551615而不是(1<<64)-2==-1
我:搞错了,无符号整型的输出占位符应该是%u而不是%D,%D不知道是干嘛用的
我:总结:
1、printf错误地将负数当成整数输出的原因:格式字符使用错误,%d写成了%ld使得编译器将-1的负号当成了数值。解决方法:%ld改回%d
2、printf将无符号数当成有符号数输出的原因:格式字符错误,本来应该用%lu却用了%ld使得编辑器将最高位当成了负号。解决方法:将%ld改为%lu。