从学习C语言开始,int类型所占字节数,以及数值范围就是一个挥之不去的问题。一开始会死记硬背一个char 1个字节,一个字节8个bit。64位机器上面一个int 4个字节,32位机器上面不一样。那时候并不知道编译器也分很多种,每一种实现的细节不一样,也不知道各家编译器是遵循C++标准委员会的标准。后来学会像编译器求证,以其输出为准,也学会向标准求证。

在一篇博客上面看到用numeric_limits 类可以方便地了解各个类型的取值范围以及占用内存,于是满心欢喜地将代码运行,发现有些问题:

#include<iostream>
#include <limits>
using namespace std; int main()
{
cout << "type: \t\t" << "------------------size-----------------------"<< endl;
cout << "bool: \t\t" << "Bytes:" << sizeof(bool);
cout << "\tMaxValue:" << (numeric_limits<bool>::max)();
cout << "\t\tMinValue:" << (numeric_limits<bool>::min)() << endl;
cout << "char: \t\t" << "Bytes:" << sizeof(char);
cout << "\tMaxValue:" << (numeric_limits<char>::max)();
cout << "\t\tMinValue:" << (numeric_limits<char>::min)() << endl;
cout << "signed char: \t" << "Bytes:" << sizeof(signed char);
cout << "\tMaxValue:" << (numeric_limits<signed char>::max)();
cout << "\t\tMinValue:" << (numeric_limits<signed char>::min)() << endl;
cout << "unsigned char: \t" << "Bytes:" << sizeof(unsigned char);
cout << "\tMaxValue:" << (numeric_limits<unsigned char>::max)();
cout << "\t\tMinValue:" << (numeric_limits<unsigned char>::min)() << endl;
cout << "wchar_t: \t" << "Bytes:" << sizeof(wchar_t);
cout << "\tMaxValue:" << (numeric_limits<wchar_t>::max)();
cout << "\t\tMinValue:" << (numeric_limits<wchar_t>::min)() << endl;
cout << "short: \t\t" << "Bytes:" << sizeof(short);
cout << "\tMaxValue:" << (numeric_limits<short>::max)();
cout << "\t\tMinValue:" << (numeric_limits<short>::min)() << endl;
cout << "int: \t\t" << "Bytes:" << sizeof(int);
cout << "\tMaxValue:" << (numeric_limits<int>::max)();
cout << "\tMinValue:" << (numeric_limits<int>::min)() << endl;
cout << "unsigned: \t" << "Bytes:" << sizeof(unsigned);
cout << "\tMaxValue:" << (numeric_limits<unsigned>::max)();
cout << "\tMinValue:" << (numeric_limits<unsigned>::min)() << endl;
cout << "long: \t\t" << "Bytes:" << sizeof(long);
cout << "\tMaxValue:" << (numeric_limits<long>::max)();
cout << "\tMinValue:" << (numeric_limits<long>::min)() << endl;
cout << "type: \t\t" << "************size**************"<< endl;
return ;
}

运行结果:

常用的int,long等类型的取值范围确实如愿显示。但是,在关于 char的判断中,有显示的问题。从使用的角度而言,其实char用于表示字符,判断大小并不合理。当然,这只是一个“完形填空”式的推导。既然显示在屏幕上的输出有问题,本着钻研精神,要弄清楚为什么。

首先是假设:

1. cout无法处理这个numeric_limit<char>::max()函数

2.numeric_limit<char>::max()的返回值并不是可显示字符。

为了验证第一点,我找到C++标准委员会的网站,找到C++14的草稿标准:

从这里看出,返回的是模板类型 T的构造函数。似乎排除了第一种可能。但标准太不具体,我在Clion上面用debug模式直接找到库文件来确认。值得一提的是编译器版本:gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.2)。

第一步:

再往下一层:

在limits的实现里面,都是再用宏定义的位操作来实现最大和最小值的获取。先看__glibcxx_digits宏定义。这里面的逻辑很简单,占用字节数乘以__CHAR_BIT__减去符号位(1位)。在char的例子里面,得出来的位数是7。从这里不妨猜测,编译器对一个字节大小的定义很有可能是基于__CHAR_BIT__的。在一篇博文看过对于古老的机器,char类型只有7bit。按照这个猜测,在描述内置int型大小的时候,就可以说一个int等于4个char。这个猜测挺有意思,不过有待考究。

进一步分析,__glicxx_min宏定义,对于传入的类型_Tp,如果有符号,就执行(_Tp)1 << _glibcxx_digits(_Tp), 没有就是(_Tp)0.

对于char型,它居然被是认为有符号的! 所以最小值的计算变成 (char)1 << 7,二进制表示10000000, -128.

一个被赋值为-128的char类型字符,其实现的动机难以理解,不过从某程度上说明标准与实现之间的距离,对于一个函数的实现,尤其是不常用的功能,最好还是自己进行确认。

从C++ int类型的变量范围谈起的更多相关文章

  1. 详解mysql int类型的长度值问题【转】

    mysql在建表的时候int类型后的长度代表什么? 是该列允许存储值的最大宽度吗? 为什么我设置成int(1), 也一样能存10,100,1000呢. 当时我虽然知道int(1),这个长度1并不代表允 ...

  2. MySQL数据类型 int(M) 表示什么意思?详解mysql int类型的长度值问题

    MySQL 数据类型中的 integer types 有点奇怪.你可能会见到诸如:int(3).int(4).int(8) 之类的 int 数据类型.刚接触 MySQL 的时候,我还以为 int(3) ...

  3. MySQL中int类型的字段使用like查询方法

    方法参考自: http://stackoverflow.com/questions/8422455/performing-a-like-comparison-on-an-int-field 也就是使用 ...

  4. int类型究竟占几个字节

    我最近也在看深入理解计算机系统这本书,上面提到了在32位机器和64机器中int类型都占用4个字节.后来,别人查了The C Programming language这本书,里面有一句话是这样的: Ea ...

  5. long l=88;这个表达式是正确的,因为long比int类型大,会发生自动转换

    long l=88;这个表达式是正确的,因为long比int类型大,会发生自动转换

  6. 使用DataOutputStream写入int类型数字不能显示

    前段时间做Android系统项目需要使用DataOutputStream数据流向文件里写入数据,写入的有String类型和int类型.写入之后在代码中使用DataInputStream读出是没有问题的 ...

  7. Android java传递int类型数组给C

    接着前面的文章<Android java传递int类型数据给C><Android java传递string类型数据给C>,继续实践 实现public native int[] ...

  8. Android java传递int类型数据给C

    本文根据<Android jni简便开发流程>中的开发流程来实现一个java传递int类型数据给C 新建项目,进行简单的布局 <LinearLayout xmlns:android= ...

  9. 用int类型表示最大公倍数

    代码 #include<stdio.h> #include<stdlib.h> #include<limits.h> int main(void) { int m, ...

随机推荐

  1. Google永远不可能回到国内,只能是回忆

    今天早上在微博上无意看 [谷歌翻译App在大陆地区恢复无障碍使用]这篇文章,不知不觉就点进去看一下,内心还是比较兴奋,为什么兴奋说不清楚.或许我们是真的喜欢Google的产品. 回想2010年Goog ...

  2. 关于bootstrap原理及优缺点

    网格系统的实现原理,是通过定义容器大小,平分12份(也有平分成24份或32份,但12份是最常见的),再调整内外边距,最后结合媒体查询,就制作出了强大的响应式网格系统.Bootstrap框架中的网格系统 ...

  3. Java中类的继承,属性和方法的四种修饰符的作用范围,final关键字,java的三大特点中的2个:封装和多态,以及多态的一个设计模式,模板方法模式(template method)

    (一)Java中的继承: 关于继承,在Java中类的继承只能是单继承,不像C+++那样灵活,可以多继承,多继承的后果就是各种关系乱套,就相当于一个孩子有2个母亲一样,社会关系的复杂,不利于程序后期的开 ...

  4. web中关于垃圾回收的一些观点

    感觉dom大神的解惑 关于引用计数法,注意引用的方向性就行.  A.addEventListner(B.func), 那么是增加了A对B的引用.如果A是不可回收的对象,比如全局的Stage,或者单例. ...

  5. 【转】使用VS开发 Node.js指南

    参考:https://www.visualstudio.com/features/node-js-vs 这篇文章主要介绍了使用VS开发 Node.js的方法,主要是使用NTVS(Node.js Too ...

  6. 【原创】Octovis在Ubuntu16.04下运行出现core dump的解决方案

    本人SLAM研究新手,使用系统为Ubuntu16.04.本文原址:http://www.cnblogs.com/hitlrk/p/6667253.html 在学习SLAM的过程中,使用Octomap进 ...

  7. Linux命令速查大全

    常用基本命令 ls 显示文件或目录 -l 列出文件详细信息l(list) -a 列出当前目录下所有文件及目录,包括隐藏的a(all) mkdir 创建目录 -p 创建目录,若无父目录,则创建p(par ...

  8. DC平衡双向控制解串器 转接IC GM8914:FPD-LINK III转LVTTL芯片

    1 概述 GM8914型DC平衡双向控制解串器,其主要功能是实现将2.8Gbps高速串行数据转换成10或12位并行控制信号,并同步输出一路时钟信号:同时低速通道将芯片控制信息调制到高速差分信号上传输给 ...

  9. asp.net core源码飘香:Options组件

    简介: Options组件是一个小组件,但用的地方很多.它本质是将一个POCO类注册到容器中(主要在Startup中作为其他组件的配置功能提供),后续使用的时候就可以通过比如构造函数注入等获取到POC ...

  10. 【LeetCode题解】排序

    1. 排序 排序(sort)是一种常见的算法,把数据根据特定的顺序进行排列.经典的排序算法如下: 冒泡排序(bubble sort) 插入排序(insertion sort) 选择排序(selecti ...