从C语言的整数取值范围说开去
在ILP32中, char, short, int, long, long long, pointer分别占1, 2, 4, 4, 8, 4个字节,
在 LP64中, char, short, int, long, long long, pointer分别占1, 2, 4, 8, 8, 8个字节,
无论是在ILP32中还是LP64中, long long总是占8个字节,下面给出简单的C代码实现表征出整数的取值范围先。
o foo.c
- #include <stdio.h>
- /**
- * The size (n bytes) of basic types
- * =================================
- * char short int long long long pointer
- * ----- ---- ----- --- ---- --------- -------
- * LP64 1 2 4 8 8 8
- * ILP32 1 2 4 4 8 4
- */
- typedef char __s8;
- typedef short __s16;
- typedef int __s32;
- typedef long long __s64;
- typedef unsigned char __u8;
- typedef unsigned short __u16;
- typedef unsigned int __u32;
- typedef unsigned long long __u64;
- #define SMAX8 ((__s8 )(((__u8 )~0) >> 1))
- #define SMAX16 ((__s16)(((__u16)~0) >> 1))
- #define SMAX32 ((__s32)(((__u32)~0) >> 1))
- #define SMAX64 ((__s64)(((__u64)~0) >> 1))
- #define SMIN8 -SMAX8
- #define SMIN16 -SMAX16
- #define SMIN32 -SMAX32
- #define SMIN64 -SMAX64
- #define UMAX8 ((__u8 )~0)
- #define UMAX16 ((__u16)~0)
- #define UMAX32 ((__u32)~0)
- #define UMAX64 ((__u64)~0)
- #define UMIN8 ((__u8 )0)
- #define UMIN16 ((__u16)0)
- #define UMIN32 ((__u32)0)
- #define UMIN64 ((__u64)0)
- int main(int argc, char *argv[])
- {
- __s8 smax8 = SMAX8;
- __s16 smax16 = SMAX16;
- __s32 smax32 = SMAX32;
- __s64 smax64 = SMAX64;
- __s8 smin8 = SMIN8;
- __s16 smin16 = SMIN16;
- __s32 smin32 = SMIN32;
- __s64 smin64 = SMIN64;
- printf("s64: [%llx, %llx]\t[%lld, %lld]\n", smin64, smax64, smin64, smax64);
- printf("s32: [%x, %x]\t\t\t[%d, %d]\n", smin32, smax32, smin32, smax32);
- printf("s16: [%x, %x]\t\t\t\t[%d, %d]\n", smin16, smax16, smin16, smax16);
- printf("s8 : [%x, %x]\t\t\t\t[%d, %d]\n", smin8, smax8, smin8, smax8);
- printf("\n");
- __u8 umax8 = UMAX8;
- __u16 umax16 = UMAX16;
- __u32 umax32 = UMAX32;
- __u64 umax64 = UMAX64;
- __u8 umin8 = UMIN8;
- __u16 umin16 = UMIN16;
- __u32 umin32 = UMIN32;
- __u64 umin64 = UMIN64;
- printf("u64: [%llx, %llx]\t\t\t[%lld, %llu]\n", umin64, umax64, umin64, umax64);
- printf("u32: [%x, %x]\t\t\t\t[%d, %u]\n", umin32, umax32, umin32, umax32);
- printf("u16: [%x, %x]\t\t\t\t\t[%d, %u]\n", umin16, umax16, umin16, umax16);
- printf("u8 : [%x, %x]\t\t\t\t\t[%d, %u]\n", umin8, umax8, umin8, umax8);
- return ;
- }
o 编译并执行
- $ gcc -g -Wall -m32 -o foo foo.c
- $ ./foo
- s64: [, 7fffffffffffffff] [-, ]
- s32: [, 7fffffff] [-, ]
- s16: [ffff8001, 7fff] [-, ]
- s8 : [ffffff81, 7f] [-, ]
- u64: [, ffffffffffffffff] [, ]
- u32: [, ffffffff] [, ]
- u16: [, ffff] [, ]
- u8 : [, ff] [, ]
注意: 二进制数在计算机中一律以补码表示。 这里简单说说二进制编码中的原码,反码以及补码(注:移码这里不谈)以帮助理解上面的输出。
1. 原码的编码规则
1.1 原码即"原始编码", 最高位为符号位,0表示整数,1表示负数;
1.2 +0和-0的原码表示是不同的。在16位机器上,
- +0 = 0000 0000 0000 0000b
- -0 = 1000 0000 0000 0000b
2. 反码的编码规则
2.1 正数的反码等于其原码;
2.2 负数的反码是符号位不变,除符号外之外的其他位按位取反;
2.3 +0和-0的反码表示也是不同的。在16位机器上,
- +0 = 0111 1111 1111 1111b
- -0 = 1111 1111 1111 1111b
3. 补码的编码规则
3.1 正数的补码等于原码;
3.2 负数的补码是符号位不变,除符号外之外的其他位按位取反,再给最低位加1;
3.3 +0和-0的补码是唯一的,都是0。在16位机器上,
- +0 = 0000 0000 0000 0000b ;= +0(反)
- -0 = 0000 0000 0000 0000b ;= -0(反)+1
4. 为什么要引入补码?
4.1 无论是原码,还是反码,都无法解决0的的二义性问题。补码的引入,解决了这一问题,也就是0的表示是唯一的;
4.2 让符号位参与运算。因此,所有减法都可以用加法器实现。
o 因为编译选项是-m32, 所以:
- -127 的补码表示是 0xffffff81 = (1111 1111 1111 1111 1111 1111 1000 0001b)
-32767 的补码表示是 0xffff8001 = (1111 1111 1111 1111 1000 0000 0000 0001b)
-2147483647 的补码表示是 0x80000001 = (1000 0000 0000 0000 0000 0000 0000 0001b)
-9223372036854775807 的补码表示是0x8000000000000001 = (1000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0001b)
以-127为例,在32位机器上,其原码、反码和补码可表示为:
o 000 0000 0000 0000 0000 0000 0111 1111b ; 原码
o 111 1111 1111 1111 1111 1111 1000 0000b ; 反码: 在原码的基础上, 符号位不变, 剩下31位按位取反
o 111 1111 1111 1111 1111 1111 1000 000b ; 补码: 在反码的基础上, 给最低位加1
小结: 将常见的整数的取值范围牢记于心,有利于在实际的程序设计中根据需求快速地确定变量(或结构体成员)的基本数据类型,写出优质无错的代码。
- 对于占N个二进制位的有符号整数, 能表示的范围是[- (2^N-1 - 1), +((2^N-1 - 1)], N=8, 16, 32, 64, ... (因为符号位占了一位,所以是N-1)
- 对于占N个二进制位的无符号整数, 能表示的范围是[0, +((2^N - 1)], N=8, 16, 32, 64, ...
另外,在做算法设计的时候,将下面的表格(2的N次方)烂熟于心也有利于快速做出判断。 例如,一个将每个32位无符号整数映射为布尔值的hash表可以将一台计算机的内存填满。
2的N次方 | 准确值 | 近似值 | K/M/G/T...表示 |
7 | 128 | ||
8 | 256 | ||
千(Thousand) | 1K | ||
65, 536 | 64K | ||
1, 048, 576 | 百万(Million) | 1M | |
1, 073, 741, 824 | 十亿(Billion) | 1G | |
4, 294, 967, 296 | 4G | ||
1, 099, 511, 627, 776 | 万亿(Trillion) | 1T |
- 1K : 2^10 : 千
- 1M : 2^20 : 百万 (Million) ; 千千
- 1G : 2^30 : 十亿 (Billion) ; 千百万
- 1T : 2^40 : 万亿 (Trillion); 千十亿
- 1E : 2^50
- 1Z : 2^60
- 256: 2^8
- 64K: 2^16
- 4G : 2^32
4Z : 2^64
从C语言的整数取值范围说开去的更多相关文章
- C语言:整数取值范转及溢出
short.int.long 是C语言中常用的三种整数类型,分别称为短整型.整型.长整型.在现代操作系统中,short.int.long 的长度分别是 2.4.4 或者 8,它们只能存储有限的数值,当 ...
- 建议 for 语句的循环控制变量的取值采用“半开半闭区间”写法
建议 for 语句的循环控制变量的取值采用“半开半闭区间”写法. #include <iostream> /* run this program using the console pau ...
- C语言中数据类型取值范围的计算的理解与总结
c语言中,数据类型有short,int,long,char,float,double,然后除了浮点型只有 有符号数(signed)外,其他的数据类型都分为有符号(signed)和无符号(unsigne ...
- 编写一个js函数,该函数有一个n(数字类型),其返回值是一个数组,该数组内是n个随机且不重复的整数,且整数取值范围是[2,32]
首先定义个fn用来返回整数的取值范围: function getRand(a,b){ var rand = Math.ceil(Math.random()*(b-a)+a); return rand; ...
- C语言各种数据类型取值范围
速查表: char -128 ~ +127 1Byte -2^7 ~ 2^7-1 unsigned char 0 ~ 255 1Byte 0 ~ 2^8-1 short -32767 ~ + 3276 ...
- 编写一个javscript函数 fn,该函数有一个参数 n(数字类型),其返回值是一个数组,该数组内是 n 个随机且不重复的整数,且整数取值范围是 [2, 32]。
function fn(n){ if(n<2 || n>32) { return; } if(!n) { return;} //判断n是否为数字 if(!/^[0-9]+.?[0-9 ...
- 带符号的char类型取值范围为什么是-128——127
以前经常看到带符号的char类型取值范围是-128——127,今天突然想为什么不是-127——127,-128是怎么来的? 127好理解,char类型是8位,最高位是符号位,0正1负,所以011111 ...
- C语言数据类型取值范围
一.获取数据类型在系统中的位数 在不同的系统中,数据类型的字节数(bytes)不同,位数(bits)也有所不同,那么对应的取值范围也就有了很大的不同,那我们怎么知道你当前的系统中C语言的某个数据类型的 ...
- GO语言学习笔记2-int类型的取值范围
相比于C/C++语言的int类型,GO语言提供了多种int类型可供选择,有int8.int16.int32.int64.int.uint8.uint16.uint32.uint64.uint. 1.i ...
随机推荐
- SQL2008中sa账户无法登陆问题
实验需要用Java与SQL Server连接,因为使用的 SQL 2008 Express Edition 是基于 Visual Studio2010 安装包安装时一起安装的,所以为了方便数据库的操作 ...
- 解决Hbuilder打包的apk文件按手机返回键直接退出软件
问题描述:Hbuilder打包的app如果点击手机返回键,app会直接退出,返回不了上一页. 写在公共js文件中,每个页面均引入该js,代码如下: document.addEventListener( ...
- Python 串口通信 GUI 开发
在项目中遇到树莓派串口通信问题.由于本人一直从事.net 开发,希望将树莓派系统换成Win10 IOT版.但是在测试过程中出现无法找到串口的问题.最终也没有解决.最终按照领导要求,linux (了解不 ...
- java 统计字符串中子字符串个数
方法一: public class StatisticalStringNumber1 { public static void main(String args[]){ String string=& ...
- 徒手CPR心脏复苏
CPR 缩写于cardiopulmonary resuscitation. 在危难时刻,能救人救命,意义极其重大,赶紧学起来 成人的CPR 第一步:检查意识 靠近其耳朵,在两耳旁交替大声喊:「你怎么了 ...
- hdu3089 Josephus again|快速约瑟夫环
题目链接:戳我 貌似是高一昨天的考试题T2?????感觉挺好玩的就搞了搞qwqwq 其实是HDU上面的题啦.... 对于普通的约瑟夫问题,大概是n个人围成一个环,从1开始报数,数到k,那个人出队,最后 ...
- 值得学习的C开源项目
C开源项目学习 原文:戳这里 1. Webbench Webbench 是一个在 linux 下使用的非常简单的网站压测工具.它使用 fork ()模拟多个客户端同时访问我们设定的 URL,测试网站在 ...
- Windows IIS ASP.NET Core中创建和使用HTTPS自签名证书
为什么要用Https就不说了. 第一步:创建自签名的证书.在Windows下开启PowerShell,将以下文字粘贴进去: # setup certificate properties includi ...
- 队列优化dijsktra(SPFA)的玄学优化
转载:大佬博客 最近想到了许多优化spfa的方法,这里想写个日报与大家探讨下 前置知识:spfa(不带任何优化) 由于使用较多 STLSTL ,本文中所有代码的评测均开启 O_2O2 优化 对一些数 ...
- P4097 [HEOI2013]Segment 李超线段树
$ \color{#0066ff}{ 题目描述 }$ 要求在平面直角坐标系下维护两个操作: 在平面上加入一条线段.记第 i 条被插入的线段的标号为 i 给定一个数 k,询问与直线 x = k 相交的线 ...