在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

  1. #include <stdio.h>
  2. /**
  3. * The size (n bytes) of basic types
  4. * =================================
  5. * char short int long long long pointer
  6. * ----- ---- ----- --- ---- --------- -------
  7. * LP64 1 2 4 8 8 8
  8. * ILP32 1 2 4 4 8 4
  9. */
  10. typedef char __s8;
  11. typedef short __s16;
  12. typedef int __s32;
  13. typedef long long __s64;
  14. typedef unsigned char __u8;
  15. typedef unsigned short __u16;
  16. typedef unsigned int __u32;
  17. typedef unsigned long long __u64;
  18.  
  19. #define SMAX8 ((__s8 )(((__u8 )~0) >> 1))
  20. #define SMAX16 ((__s16)(((__u16)~0) >> 1))
  21. #define SMAX32 ((__s32)(((__u32)~0) >> 1))
  22. #define SMAX64 ((__s64)(((__u64)~0) >> 1))
  23.  
  24. #define SMIN8 -SMAX8
  25. #define SMIN16 -SMAX16
  26. #define SMIN32 -SMAX32
  27. #define SMIN64 -SMAX64
  28.  
  29. #define UMAX8 ((__u8 )~0)
  30. #define UMAX16 ((__u16)~0)
  31. #define UMAX32 ((__u32)~0)
  32. #define UMAX64 ((__u64)~0)
  33.  
  34. #define UMIN8 ((__u8 )0)
  35. #define UMIN16 ((__u16)0)
  36. #define UMIN32 ((__u32)0)
  37. #define UMIN64 ((__u64)0)
  38.  
  39. int main(int argc, char *argv[])
  40. {
  41. __s8 smax8 = SMAX8;
  42. __s16 smax16 = SMAX16;
  43. __s32 smax32 = SMAX32;
  44. __s64 smax64 = SMAX64;
  45. __s8 smin8 = SMIN8;
  46. __s16 smin16 = SMIN16;
  47. __s32 smin32 = SMIN32;
  48. __s64 smin64 = SMIN64;
  49. printf("s64: [%llx, %llx]\t[%lld, %lld]\n", smin64, smax64, smin64, smax64);
  50. printf("s32: [%x, %x]\t\t\t[%d, %d]\n", smin32, smax32, smin32, smax32);
  51. printf("s16: [%x, %x]\t\t\t\t[%d, %d]\n", smin16, smax16, smin16, smax16);
  52. printf("s8 : [%x, %x]\t\t\t\t[%d, %d]\n", smin8, smax8, smin8, smax8);
  53. printf("\n");
  54.  
  55. __u8 umax8 = UMAX8;
  56. __u16 umax16 = UMAX16;
  57. __u32 umax32 = UMAX32;
  58. __u64 umax64 = UMAX64;
  59. __u8 umin8 = UMIN8;
  60. __u16 umin16 = UMIN16;
  61. __u32 umin32 = UMIN32;
  62. __u64 umin64 = UMIN64;
  63. printf("u64: [%llx, %llx]\t\t\t[%lld, %llu]\n", umin64, umax64, umin64, umax64);
  64. printf("u32: [%x, %x]\t\t\t\t[%d, %u]\n", umin32, umax32, umin32, umax32);
  65. printf("u16: [%x, %x]\t\t\t\t\t[%d, %u]\n", umin16, umax16, umin16, umax16);
  66. printf("u8 : [%x, %x]\t\t\t\t\t[%d, %u]\n", umin8, umax8, umin8, umax8);
  67.  
  68. return ;
  69. }

o 编译并执行

  1. $ gcc -g -Wall -m32 -o foo foo.c
  2. $ ./foo
  3. s64: [, 7fffffffffffffff] [-, ]
  4. s32: [, 7fffffff] [-, ]
  5. s16: [ffff8001, 7fff] [-, ]
  6. s8 : [ffffff81, 7f] [-, ]
  7.  
  8. u64: [, ffffffffffffffff] [, ]
  9. u32: [, ffffffff] [, ]
  10. u16: [, ffff] [, ]
  11. u8 : [, ff] [, ]

注意: 二进制数在计算机中一律以补码表示。 这里简单说说二进制编码中的原码,反码以及补码(注:移码这里不谈)以帮助理解上面的输出。

1. 原码的编码规则
1.1 原码即"原始编码", 最高位为符号位,0表示整数,1表示负数;
1.2 +0和-0的原码表示是不同的。在16位机器上,

  1. +0 = 0000 0000 0000 0000b
  2. -0 = 1000 0000 0000 0000b

2. 反码的编码规则
2.1 正数的反码等于其原码;
2.2 负数的反码是符号位不变,除符号外之外的其他位按位取反;
2.3 +0和-0的反码表示也是不同的。在16位机器上,

  1. +0 = 0111 1111 1111 1111b
  2. -0 = 1111 1111 1111 1111b

3. 补码的编码规则
3.1 正数的补码等于原码;
3.2 负数的补码是符号位不变,除符号外之外的其他位按位取反,再给最低位加1;
3.3 +0和-0的补码是唯一的,都是0。在16位机器上,

  1. +0 = 0000 0000 0000 0000b ;= +0(反)
  2. -0 = 0000 0000 0000 0000b ;= -0(反)+1

4. 为什么要引入补码?
4.1 无论是原码,还是反码,都无法解决0的的二义性问题。补码的引入,解决了这一问题,也就是0的表示是唯一的;
4.2 让符号位参与运算。因此,所有减法都可以用加法器实现。

o 因为编译选项是-m32, 所以:

  1. -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
  1. 1K : 2^10 :
  2. 1M : 2^20 : 百万 (Million) ; 千千
  3. 1G : 2^30 : 十亿 (Billion) ; 千百万
  4. 1T : 2^40 : 万亿 (Trillion); 千十亿
  5. 1E : 2^50
  6. 1Z : 2^60
  7. 256: 2^8
  8. 64K: 2^16
  9. 4G : 2^32
    4Z : 2^64

从C语言的整数取值范围说开去的更多相关文章

  1. C语言:整数取值范转及溢出

    short.int.long 是C语言中常用的三种整数类型,分别称为短整型.整型.长整型.在现代操作系统中,short.int.long 的长度分别是 2.4.4 或者 8,它们只能存储有限的数值,当 ...

  2. 建议 for 语句的循环控制变量的取值采用“半开半闭区间”写法

    建议 for 语句的循环控制变量的取值采用“半开半闭区间”写法. #include <iostream> /* run this program using the console pau ...

  3. C语言中数据类型取值范围的计算的理解与总结

    c语言中,数据类型有short,int,long,char,float,double,然后除了浮点型只有 有符号数(signed)外,其他的数据类型都分为有符号(signed)和无符号(unsigne ...

  4. 编写一个js函数,该函数有一个n(数字类型),其返回值是一个数组,该数组内是n个随机且不重复的整数,且整数取值范围是[2,32]

    首先定义个fn用来返回整数的取值范围: function getRand(a,b){ var rand = Math.ceil(Math.random()*(b-a)+a); return rand; ...

  5. C语言各种数据类型取值范围

    速查表: char -128 ~ +127 1Byte -2^7 ~ 2^7-1 unsigned char 0 ~ 255 1Byte 0 ~ 2^8-1 short -32767 ~ + 3276 ...

  6. 编写一个javscript函数 fn,该函数有一个参数 n(数字类型),其返回值是一个数组,该数组内是 n 个随机且不重复的整数,且整数取值范围是 [2, 32]。

    function fn(n){ if(n<2 || n>32) { return; }  if(!n) { return;}  //判断n是否为数字  if(!/^[0-9]+.?[0-9 ...

  7. 带符号的char类型取值范围为什么是-128——127

    以前经常看到带符号的char类型取值范围是-128——127,今天突然想为什么不是-127——127,-128是怎么来的? 127好理解,char类型是8位,最高位是符号位,0正1负,所以011111 ...

  8. C语言数据类型取值范围

    一.获取数据类型在系统中的位数 在不同的系统中,数据类型的字节数(bytes)不同,位数(bits)也有所不同,那么对应的取值范围也就有了很大的不同,那我们怎么知道你当前的系统中C语言的某个数据类型的 ...

  9. GO语言学习笔记2-int类型的取值范围

    相比于C/C++语言的int类型,GO语言提供了多种int类型可供选择,有int8.int16.int32.int64.int.uint8.uint16.uint32.uint64.uint. 1.i ...

随机推荐

  1. SQL2008中sa账户无法登陆问题

    实验需要用Java与SQL Server连接,因为使用的 SQL 2008 Express Edition 是基于 Visual Studio2010 安装包安装时一起安装的,所以为了方便数据库的操作 ...

  2. 解决Hbuilder打包的apk文件按手机返回键直接退出软件

    问题描述:Hbuilder打包的app如果点击手机返回键,app会直接退出,返回不了上一页. 写在公共js文件中,每个页面均引入该js,代码如下: document.addEventListener( ...

  3. Python 串口通信 GUI 开发

    在项目中遇到树莓派串口通信问题.由于本人一直从事.net 开发,希望将树莓派系统换成Win10 IOT版.但是在测试过程中出现无法找到串口的问题.最终也没有解决.最终按照领导要求,linux (了解不 ...

  4. java 统计字符串中子字符串个数

    方法一: public class StatisticalStringNumber1 { public static void main(String args[]){ String string=& ...

  5. 徒手CPR心脏复苏

    CPR 缩写于cardiopulmonary resuscitation. 在危难时刻,能救人救命,意义极其重大,赶紧学起来 成人的CPR 第一步:检查意识 靠近其耳朵,在两耳旁交替大声喊:「你怎么了 ...

  6. hdu3089 Josephus again|快速约瑟夫环

    题目链接:戳我 貌似是高一昨天的考试题T2?????感觉挺好玩的就搞了搞qwqwq 其实是HDU上面的题啦.... 对于普通的约瑟夫问题,大概是n个人围成一个环,从1开始报数,数到k,那个人出队,最后 ...

  7. 值得学习的C开源项目

    C开源项目学习 原文:戳这里 1. Webbench Webbench 是一个在 linux 下使用的非常简单的网站压测工具.它使用 fork ()模拟多个客户端同时访问我们设定的 URL,测试网站在 ...

  8. Windows IIS ASP.NET Core中创建和使用HTTPS自签名证书

    为什么要用Https就不说了. 第一步:创建自签名的证书.在Windows下开启PowerShell,将以下文字粘贴进去: # setup certificate properties includi ...

  9. 队列优化dijsktra(SPFA)的玄学优化

    转载:大佬博客 最近想到了许多优化spfa的方法,这里想写个日报与大家探讨下 前置知识:spfa(不带任何优化) 由于使用较多 STLSTL ,本文中所有代码的评测均开启 O_2O2​ 优化 对一些数 ...

  10. P4097 [HEOI2013]Segment 李超线段树

    $ \color{#0066ff}{ 题目描述 }$ 要求在平面直角坐标系下维护两个操作: 在平面上加入一条线段.记第 i 条被插入的线段的标号为 i 给定一个数 k,询问与直线 x = k 相交的线 ...