从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 ...
随机推荐
- C#多线程编程实战1.1创建线程
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...
- C++友元(友元函数、友元类和友元成员函数)
友元(友元函数.友元类和友元成员函数) C++ 有些情况下,允许特定的非成员函数访问一个类的私有成员,同时仍阻止一般的访问,这是很方便做到的.例如被重载的操作符,如输入或输出操作符,经常需要访问类的私 ...
- python之爬虫(二)爬虫的原理
在上文中我们说了:爬虫就是请求网站并提取数据的自动化程序.其中请求,提取,自动化是爬虫的关键!下面我们分析爬虫的基本流程 爬虫的基本流程 发起请求通过HTTP库向目标站点发起请求,也就是发送一个Req ...
- ubuntu安装ICE记录
背景本文档介绍在unbuntu环境下如何安装ICE,并用C++写一个ICE应用 ICE简介ICE是ZEROC的开源通信协议产品,它的全称是:The Internet Communications En ...
- windows server2008 r2安装DNS服务器
1.开始->管理工具->服务器管理器 2.角色->添加角色 3.服务器角色->DNS服务器 4.一直点击下一步,直至安装完成. (确认步骤时会提示,可能会需要重启服务器) 安装 ...
- Zabbix监控详解
Zabbix是什么 Zabbix 是由Alexei Vladishev创建,目前由Zabbix SIA在持续开发和支持. Zabbix 是一个企业级的分布式开源监控方案. Zabbix是一款能够监控各 ...
- 一款不错的jQuery分页插件--pagination
一.前言: 分页功能在项目中时常用到,一款可以快速实现分页功能的插件非常有必要,pagination--这款插件功能非常完美,几乎我所有项目中使用到分页的地方都会第一时间考虑到这个插件,但是其实有能力 ...
- c语言-勒让德多项式求解+时间测定
#include<iostream>#include<ctime>#include<cstdlib>using namespace std; float LRD(i ...
- Tutorial 01 4,5题
.任务四: 程序设计思想:利用Math.random()产生一个char类型的字符,再利用for循环是他们相加,最后将他们放在一个消息框中输出. 程序流程图: 源程序: p ...
- 51 Nod 1050 dp
1050 循环数组最大子段和 1 秒 131,072 KB 10 分 2 级题 N个整数组成的循环序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的连 ...