c语言里面,为什么双单精度和整型强制转成整型会不见小数部分?按照数位的知识来说是怎么样的?

整型提升:
K&R C中关于整型提升(integral promotion)的定义为:
&A character, a short integer, or an integer bit-field, all either signed or not, or an object of enumeration type, may be used in an expression wherever an integer maybe used. If an int can represent all the values of the original
type, then the value otherwise the value is converted to unsigned int. This process is called integral promotion.&
上面的定义归纳下来就是以下两个原则:
1).&只要一个表达式中用到了整型值,那么类型为char、short int或整型位域(这几者带符号或无符号均可)的变量,以及枚举类型的对象,都可以被放在这个整型变量的位置。
2).&如果1)中的变量的原始类型值域可以被int表示,那么原值被转换为int;否则的话,转为unsigned int。
以上两者作为一个整体,被成为整型提升(Integral promotion)
整型提升的概念容易与普通算术类型转换产生混淆。这两者的区别之一在于后者是在操作数之间类型不一致的情况下发生,最终将操作数转换为同一类型。而在算术运算这种情景下,即使操作数具有相同的类型,仍有可能发生整型提升。
&span style=&font-size:14&&char a, b,
c = a +&/span&
在上述过程中,尽管两个运算符&+&和&=&的操作数全为char型,但在中间计算过程中存在着整型提升:对于表达式a+b&,a、b都是char型,因此被提升至int型后,执行“+”运算,计算结果(int型)再赋值给c(char型),又执行了隐式的类型转换。
理解了整型提升的概念后,面对下面这个C语言的FAQ,你应该不会产生困惑。
&pre name=&code& class=&cpp&&&span style=&font-size:14&&
printf(“sizeof(a)=%d”, sizeof(a));&/span&
原因:a不是一个表达式,a是char型,char型占1字节。
&span style=&font-size:14&&printf(“sizeof(‘A’) = %d”, sizeof(‘A’));&/span&
原因:字符‘A’是int型,不需整型提升,int型占4字节
&span style=&font-size:14&&char a,
printf(“sizeof(a+b)=%d”, sizeof(a+b));&/span&
原因:a+b是一个算术表达式,a、b均整型提升(int型),所以占4个字节。
&span style=&font-size:14&&char a, b,
printf(“sizeof(c=a+b)=%d”, sizeof(c=a+b));&/span&
原因:表达式c=a+b中,a和b是算术运算,因此整型提升(int型),计算结果(int型)再赋值给c(char型),又执行了隐式的类型转换,所以最终占1字节。
运算过程中的隐式数据转换如下:
& &double&& & &← & float 高
 unsigned
  &int & & & & &← & char,short 低
参数传递:
另一个可能发生隐式参数转换的地方就是参数传递。
&在K&R C中,由于函数的参数也是表达式,所以也会发生类型提升。
在ANSI C中,如果使用了适当的函数原型,类型提升便不会发生,否则也会发生。
在被调用函数的内部,提升后的参数被裁减为原先声明的大小。
这就是为什么单个的printf()格式字符串%d能适用于几个不同类型,
short、char或int,而不论实际传递的是上述类型的哪一个。
函数从堆栈中(或寄存器中)取出的参数总是int类,并在printf或其他被调用函数里按统一的格式处理。
printf是一个可变参数函数,此时一般的参数提升始终会发生。
消除形参与实参之间的整型提升:
ANSI C函数原型的目的是使C语言成为一种更加可靠的语言。建立原型就是为了消除形参和实参之间的类型不匹配。
如果使用了函数原型,缺省参数提升就不会发生。如果参数声明为char,则实际传递的也是char。
截断/赋值中的类型转换:
当赋值运算符两边的运算对象类型不同时,将要发生类型转换, 转换的规则是:把赋值运算符右侧表达式的类型转换为左侧变量的类型。具体的转换如下:
  (1) 浮点型与整型
  ● 将浮点数(单双精度)转换为整数时,将舍弃浮点数的小数部分, 只保留整数部分。
  将整型值赋给浮点型变量,数值不变,只将形式改为浮点形式, 即小数点后带若干个0.
注意:整型转浮点型可能是不准确的:
种类-------符号位-------------指数位----------------尾数位---- float-----第31位(占1bit)---第30-23位(占8bit)----第22-0位(占23bit) double--第63位(占1bit)---第62-52位(占11bit)---第51-0位(占52bit) int-------第31位(占1bit)--------------------------第30-0位(占31bit)
取值范围主要看指数部分: float的指数部分有8bit(2^8),由于是有符号型,所以得到对应的指数范围-128~128。 double的指数部分有11bit(2^11),由于是有符号型,所以得到对应的指数范围-。 由于float的指数部分对应的指数范围为-128~128,所以取值范围为: -2^128到2^128,约等于-3.4E38 — +3.4E38 精度(有效数字)主要看尾数位: float的尾数位是23bit,对应7~8位十进制数,所以有效数字有的编译器是7位,也有的是8位,也即一个整数转换为float的话,会表示成科学计数法,由小数(精度)和指数构成,对0,1四舍五入。int可以稳式转换成float和double,float只能强制转换成int,但是可以隐式转换成double,double只能强制转换成float和int。
  在说明问题之前,还很有必要温习一下计算机组成原理时学习到的一些知识,就是二进制补码表示以及浮点数表示。我想把一个十进制转化为二进制的方法已经不用多费唇舌,只不过为了计算方便以及消除正零与负零的问题,现代计算机技术,内存里存的都是二进制的补码形式,当然这个也没什么特别的,只不过有某些离散和点,需要特殊定义而已,比如-(2^31),这个数在int的补码里表示成1000…(31个零),这个生套补码计算公式并不能得到结果(其实不考虑进位的话还真是这个结果,但是总让人感觉很怪)。再者,浮点数,其实就是把任何二进制数化成以0.1....开头的科学计数法表示而已。
  废话说完,这就出现了几个问题,而且是比较有意思的问题。
&span style=&font-size:14&&int i = Int32.MaxV
int j = (int)f;
bool b = i ==&/span&
  这里的b,是false。刚才这个操作,如果我们把float换成long,第一次进行隐式转换,第二次进行强制转换,结果将会是true。乍一看,float.MaxValue是比int.MaxValue大了不知道多少倍的,然而这个隐式转换中,却造成了数据丢失。int.MaxValue,这个&#20540;等于<span style="color:#ff-1,写成二进制补码形式就是01111…(31个1),这个数,在表示成float计数的科学计数法的时候,将会写成&#43;0.1111…(23个1)*2^31,对于那31个1,里面的最后8个,被float无情的抛弃了,因此,再将这个float强制转换回int的时候,对应的int的二进制补码表示已经变成了0111…(23个1),这个数与最初的那个int相差了255,所以造成了不相等。
  那么提出另一个问题,什么样的int变成float再变回来,和从前的&#20540;相等呢?这个问题其实完全出在那23位float的数据位上了。对于一个int,把它写成二进制形式之后,成为了个一32个长度的0、1的排列,对于这个排列,只要第一个1与最后一个1之前的间距,不超过23,那么它转换成&float再转换回来,两个&#20540;就会相等。这个问题是与大小无关的,而且这个集合在int这个全集下并不连续。
&span style=&font-size:14&&double d = 0.6;
float f = (float)d;
double d2 =
bool b = d == d2;&/span&
  这里的b,也是false。刚才这个操作,如果开始另d等于0.5,结果就将会是true。乍一看,0.6这个数这么短,double和float都肯定能够表示,那么转换过去再转换回来,结果理应相等。其实这是因为我们用十进制思考问题太久了,如果我们0.6化成二进制小数,可以发现得到的结果是0.……(1001循环)。这是一个无限循环小数。因此,不管float还是double,它在存储0.6&的时候,都无法完全保存它精确的&#20540;(计算机不懂分数,呵呵),这样的话由于float保存23位,而double保存52位,就造成了double转化成&float的时候,丢失掉了一定的数据,非再转换回去的时候,那些丢掉的&#20540;被补成了0,因此这个后来的double和从前的double&#20540;已经不再一样了。
  这样就又产生了一个问题,什么样的double转换成float再转换回来,两个的&#20540;相等呢?其实这个问题与刚才int的那个问题惊人的相&#20284;(废话,都和float打交道,能不相&#20284;么),只不过我们还需要考虑double比float多了3位的指数位,太大的数double能表示但float&不行。
  还有一个算是数学上的问题,什么样的十进制小数,表示成二进制不是无限小数呢?这个问题可以说完全成为数学范畴内的问题了,但是比较简单,答案也很明显,对于所有的最后一位以5结尾的十进制有限小数,都可以化成二进制的有限小数(虽然这个小数可能长到没谱)。
  最后,一个有意思有问题,刚才说过0.6表示成为二进制小数之后,是0.1001并且以1001为循环节的无限循环小数,那么在我们将它存成浮点数的时候,一定会在某个位置将它截断(比如float的23位和double的52位),那么真正存在内存里的这个二进制数,转化回十进制,到底是比原先的十进制数大呢,还是小呢?答案是It
depends。人计算十进制的时候,是四舍五入,计算机再计算二进制小数也挺简单,就是0舍1入。对于float,要截断成为23位,假如卡在24位上的是1,那么就会造成进位,这样的话,存起来的&#20540;就比真正的十进制&#20540;大了,如果是0,就舍去,那么存起来的&#20540;就比真正的十进制&#20540;小了。因此,这可以合理的解释一个问题,就是0.6d转换成float再转换回double,它的&#20540;是0.85791,这个&#20540;是比0.6大的,原因就是&0.6的二进制科学计数法表示,第24位是1,造成了进位。
  到了这里,仍然有一事不解,就是对于浮点数,硬件虽然给予了计算上的支持,但是它与十进制之间的互相转换,到底是如何做到的呢,又是谁做的呢(汇编器还是编译器)。这个东西突出体现在存在内存里的数明显实际与0.6不等,但是无论哪种语言,都能够在Debug以及输入的时候,将它正确的显示成&0.6提供给用户(程序员),最好的例子就是double和ToString方法,如果我写double
d=0.99999,d.ToString()给我的是0.6。诚然,对于double来说,我写的那个N长的数与0.6在内存里存的东西是一样的,但是计算机,又如果实现了将一个实际与0.6不相等的数变回0.6并显示给我的呢?
  (2) 单、双精度浮点型
  ● 由于c语言中的浮点&#20540;总是用双精度表示的,所以float 型数据只是在尾部加0延长为doub1e型数据参加运算,然后直接赋&#20540;。doub1e型数据转换为float型时,通过截尾数来实现,截断前要进行四舍五入操作。
  (3) char型与int型
  ● int型数&#20540;赋给char型变量时,只保留其最低8位,高位部分舍弃。
  ● chr型数&#20540;赋给int型变量时, 一些编译程序不管其&#20540;大小都作正数处理,而另一些编译程序在转换时,若char型数据&#20540;大于127,就作为负数处理。对于使用者来讲,如果原来char型数据取正&#20540;,转换后仍为正&#20540;;如果原来char型&#20540;可正可负,则转换后也仍然保持原&#20540;, 只是数据的内部表示形式有所不同。
另有说法:
无符号数截断时,截断后数仍为无符号
有符号数截断时,自动把截断后的数转换为无符号
  (4) int型与1ong型
  ● long型数据赋给int型变量时,将低16位&#20540;int型变量,而将高16 位截断舍弃。(这里假定int型占两个字节)。
  将int型数据送给long型变量时,其外部&#20540;保持不变,而内部形式有所改变。
  (5) 无符号整数
  ● 将一个unsigned型数据赋给一个占据同样长度单元的整型变量时(如:unsigned→int、unsigned long→long,unsigned short→short) ,原&#20540;照赋,内部的存储方式不变,但外部&#20540;却可能改变。
  ● 将一个非unsigned整型数据赋给长度相同的unsigned型变量时, 内部存储形式不变,但外部表示时总是无符号的。
  /*例:赋&#20540;运算符举例 */
&span style=&font-size:14&&  main()
unsigned a,b;
printf(“(unsigned)%u→(int)%d ”,a,j);
printf(“(int)%d→(unsigned)%u ”,i,b);
  }&/span&
  运行结果为:
  (unsigned)65535→(int)-1
  (int)-1→(unsigned)65535
  ● 计算机中数据用补码表示,int型量最高位是符号位,为1时表示负&#20540;,为0时表示正&#20540;。如果一个无符号数的&#20540;小于32768则最高位为0,赋给 int型变量后、得到正&#20540;。如果无符号数大于等于32768,则最高位为1, 赋给整型变量后就得到一个负整数&#20540;。反之,当一个负整数赋给unsigned
型变量时,得到的无符号&#20540;是一个大于32768的&#20540;。
  ● c语言这种赋&#20540;时的类型转换形式可能会使人感到不精密和不严&#26684;,因为不管表达式的&#20540;怎样,系统都自动将其转为赋&#20540;运算符左部变量的类型。
  ● 而转变后数据可能有所不同,在不加注意时就可能带来错误。 这确实是个缺点,也遭到许多人们批评。但不应忘记的是:c面言最初是为了替代汇编语言而设计的,所以类型变换比较随意。当然, 用强制类型转换是一个好习惯,这样,至少从程序上可以看出想干什么。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:77417次
积分:1034
积分:1034
排名:千里之外
转载:105篇
(7)(6)(35)(61)(1)(1)(1)(1)欢迎加入我们,一同切磋技术。 &
用户名: &&&
密 码: &
共有 29578 人关注过本帖
标题:C语言中单精度和双精度浮点型数据的数值范围是多少?怎么算出来的?请大虾帮 ...
等 级:新手上路
帖 子:20
结帖率:75%
&&已结贴√
&&问题点数:20&&回复次数:8&&&
C语言中单精度和双精度浮点型数据的数值范围是多少?怎么算出来的?请大虾帮忙了!
如题,最好能给出详尽的解释,谢谢大虾了!
搜索更多相关主题的帖子:
来 自:陕西西安
等 级:小飞侠
帖 子:705
专家分:2271
实数的计算机内部表示由具体系统规定,其中不少系统采用通行的国际标准(IEEE 标准,IEEE 是电子电器工程师协会,是一个著名的国际性技术组织):
(1)&&浮点类型的数用4个字节32位二进制表示。这样表示的数大约有7位十进制有效数字,数值的表示范围约为±(3.4×10^38…3.4×10^38);
(2)&&双精度类型的数用8个字节64位二进制表示,双精度数大约有16位十进制有效数字,数值的表示范围约为±(1.7×10^308…1.7×10^308);
(3)&&长双精度类型的数用10个字节80位二进制表示,大约有19位十进制有效数字,其数值的表示范围约为±(1.2×10^×10^4932)
[ 本帖最后由 jack10141 于
12:35 编辑 ]
Coding就像一盒巧克力,你永远不会知道你会遇到什么BUG
别跟我说你是不能的,这让我愤怒,因为这侮辱了你的智慧
来 自:魔術の禁書目錄
等 级:小飞侠
帖 子:952
专家分:2929
单精度规定用8位二进制表示阶数,即最大表示为2的128次方,把这个数算出来是3.
双精度规定用11位二进制表示阶数,即最大表示为2的1024次方,结果是1.8
永远为正义而奋斗,锄强扶弱的Level 5 超能力者
とある魔術の禁書目錄インデックス__御み坂さか美み琴こと
等 级:论坛游民
帖 子:36
专家分:24
float(单精度说明符),double(双精度说明符)
单精度型占4个字节(32位)内存空间,其数值范围为3.4E-38~3.4E+38,只能提供七位有效数字。双精度型占8 个字节(64位)内存空间,其数值范围为1.7E-308~1.7E+308,可提供16位有效数字。
等 级:新手上路
帖 子:20
float的有效数字是6~7位,double的有效数字是15~16位。。。是怎么算出来的?
来 自:魔術の禁書目錄
等 级:小飞侠
帖 子:952
专家分:2929
单精度8位阶码,1位符号,剩下23位尾数,算出2的负23次方,得到0.
前面0有多少个,就表示能精确到那一位
双精度11位阶码,1位符号,剩下52位尾数,算出2的负52次方,得到0.
前面0有多少个,就表示能精确到那一位
御坂御坂御坂详细地计算解释道
很详细,赞!
永远为正义而奋斗,锄强扶弱的Level 5 超能力者
とある魔術の禁書目錄インデックス__御み坂さか美み琴こと
等 级:新手上路
帖 子:15
学习了。。。
等 级:新手上路
帖 子:239
厉害,现在才明白,给学生都没讲清楚(兼职)非常感谢
来 自:China
等 级:业余侠客
帖 子:183
专家分:258
以下是引用御坂美琴在 13:44:02的发言:
单精度8位阶码,1位符号,剩下23位尾数,算出2的负23次方,得到0.
前面0有多少个,就表示能精确到那一位
双精度11位阶码,1位符号,剩下52位尾数,算出2的负52次方,得到0.
前面0有多少个,就表示能精确到那一位
御坂御坂御坂详细地计算解释道
精彩,网上查了好久都没找到好结果.这下懂了 嘿嘿
学如逆水行舟,不进则退
士不可以不弘毅,任重而道远
版权所有,并保留所有权利。
Powered by , Processed in 0.076148 second(s), 9 queries.
Copyright&, BCCN.NET, All Rights Reserved扫描或点击关注中金在线客服
下次自动登录
其它账号登录:
数据加载中...
数据加载中...
浏览过该文章的人还浏览过
数据加载中...
数据加载中...
数据加载中...
下列资料即小编整理的“C语言:表达式”知识点,仅供参考。
表达式是由常量、变量、运算符组合,计算以后返回一个结果值,表达式的结束标志是分号(;)。
在C语言中,所有的语句和声明都是用分号结束,在分号出现之前,语句是不完整的。
Counter/3+5;
表达式本身什么事情都不做,只是返回结果值。在程序不对返回的结果值做任何操作的情况下,返回的结果值不起任何作用。
表达式的作用有两点:
一是放在赋值语句的右边;
二是作为函数的参数。
表达式返回的结果值是有类型的。表达式隐含的数据类型取决于组成表达式的变量和常量的类型。因此,表达式的返回值有可能是某种大小的整型,或者是某精度的浮点型,或者是某种指针类型。
这里就有类型转化的问题了,类型转化的原则是从低级向高级自动转化(除非人为的加以控制)。计算的转换顺序基本是:
字符型--&整型--&长整型--&浮点型--&单精度型--&双精度型
当字符型和整型在一起运算时,结果为整型;如果整型和浮点型在一起运算,所得的结果就是浮点型,如果有双精度型参与运算,那么答案就是双精度型了。
强制转换是在类型说明符的两边加上括号,就把后面的变量转换成所要的类型了。
第一个是把a转换成整型,如果原先有小数部分,则舍去。
第二个是把b转换成浮点型,如果原先是整数,则在后面补0。
每一个表达式的返回值都具有逻辑特性,如果返回值为非0,则该表达式返回值为真,否则为假。这种逻辑特性可以用在程序流程控制语句中。
有时表达式也不参加运算。
if(a||b) …………
5&3?a++:b++;
当a为真时,b就不参加运算了,因为不管b如何,条件总是真。
有思想的财经媒体人都在这里!
是否确认删除这篇文章?
是否确认将这个粉丝放进黑名单?
是否确认这条留言删除?
您确定要删除这条信息?
用手机或者平板电脑扫描应用拍下上方二维码,可以在手机博客继续浏览文本,也可以分享给你的联系人。
以下资料仅供联系使用,请放心填写。
*您的姓名:
*联系电话:
我要给飞雀教育256送鲜花
您将赠送(朵)鲜花给:飞雀教育256
(1鲜花 = 0.1人民币)
附言:(不超过100字)
可用金币:
可用人民币元
您还需要支付0元人民币LINUX-C成长之路(二):基本数据类型 - 推酷
LINUX-C成长之路(二):基本数据类型
C语言是一种强数据类型编程语言,换句话讲,不像弱数据类型的语言比如shell脚本语言那样,没有特殊的变量数据类型,统统都是字符串。而C语言是有严格的数据类型的规定的。来看一下下面这段代码:
//example2.c
#include &stdio.h&
int main(void)
char c = 'A';
int i = 100;
float f1 = 3.14;
double f2 = 2.69E-12;
printf(&%c, %d, %f, %lf\n&, c, i, f1, f2);
这是一段最简单的代码,程序定义了4个类型不一的变量,它们分别是char型变量c,int型变量i,float型变量f1,和double型变量f2. 而且在定义的时候给它们分别进行了初始化。
首先来观察一下这个语句:
char c = 'A';
这是一个定义语句,这条语句的确切含义是:要求系统为我开辟一块内存空间,用来存放一种称之为 char 类型的数据。其中标识符 c 就是这块内存空间的名字,因此这是一块有名内存(后面会提到匿名内存),我们可以通过 c 这个名字来访问这块内存。
那么这块内存空间 c 有多大呢? 这跟定义时指明的数据类型相关,由于定义的时候指明是 char 类型,因此这块内存的大小就是 1 个字节(即 1 byte,亦即 8 bits)。
另外更为重要的是,由于定义时指明了这块内存的数据类型是 char ,因此以后程序在解释这块内存 c 时就会将它解释成一个 字符,而不是一个浮点数。这里必须搞清楚的一点是:在内存中只有1和0组成的数据序列,定义时规定的数据类型就是用来告诉系统,将来拿到一块充满了1和0的内存时,该怎么去解释它,因此不同的解释方法,将会得到完全不同的结果。
上面的定义 char c = 'A', 第一步,在内存中开辟了一块空间,名字叫 c ,而且专门用来存放字符(亦即char型)数据,紧接着我们就将字符常量 'A' 赋值给 c ,这里有个问题,字符常量 'A' 是怎么放进去这块内存的呢? 不可能在内存单元里面刻了一个字母 'A' 吧?
答案当然是否定的,内存中根本不可能存储一个字母'A',因为内存只能存储1和0. 怎么办呢? 很简单,人为规定一个数字来对应字母'A'就可以了,比如就用65吧,既然我们无法真正存储字母 ‘A',那就存储65吧! 不用担心你的'A'会丢失,因为按照这个规定,以后我们凡是遇到 char 型的单字节内存,而且里面如果恰好是一个65,我们就知道,哦!原来这家伙是'A'!
完全一样的道理,我们也无法真正存储字母'B','C','D',以及任何其他可见或不可见字符,比如 '@' &'#' &'$' &'!'&'~' &'\n' &'\b' 等等,所有这些字符都必须统统像'A'那样用一个数字来代替它们,于是,我们就有了所谓的ASCII码表。亦即数字 -- 字符 对照表。
我们可以在ubuntu的man帮助手册中查看ASCII码表:
vincent@ubuntu:~$ man ascii
上图是ASCII码表的一部分,我们现在很清楚地知道:在计算机的内存中,实际上是不存在字符的,而仅仅存放代表这些字符的数字,我们将这些人为规定的数字称为这些字符的ASCII码值。
现在回过头来再看看这个定义语句: char &c = 'A' ;
这句话的含义是:在内存中开辟一块空间(1个字节),并命名为 c , 并且与此同时,将字母‘A' 的ASCII码值65放到这个字节里面。
再来看定义语句 int i = 100;
现在理解起来就很容易了:在内存中开辟一块空间(4个字节),并命名为 i ,并且与此同时,将 100 放到这块内存中。
同理,对于float f2 = 3.14 和 float f2 = 2.69E-12 而言:在内存中开辟了两块空间(4字节和8字节),并且与此同时,将3.14和2.69 乘以 10 的 -12 次方放到这两块内存中。 现在来考虑一下整型int,int 的意思是 integer ,亦即整数。显然 int 就是专门用来存放整型数据的。比如 int i = ; &其真实的物理存储如下:
这里的 int 类型占用了内存中的4个字节,但这并不是绝对的,实际上,int 类型究竟会占几个字节,要根据具体的软硬件平台而定,C语言标准并没有规定 int 类型要占用几个字节,这样的结果是不同平台的 int 型变量的长度的不一致性,这将导致程序的移植问题。(稍后我们会看到如何解决这个问题)
从上图中可以看到,程序在存储数字的时候,都是用二进制来存储的,比如上面的 i 的值,相当于二进制 1 。这就是整型数据在内存中的存储。 另外我们要注意,最高位实际上是一个符号位,那意味着:假如最高位是0,则这是一个正数,假如最高位是1,则这是一个负数。当最高位是1时,这个负数是以补码的方式存储的,比如:
补码是真正的物理存储格式。也就是说,整型数据 -9, 在内存中的表示是: 11 .&(4个字节)
另外,有时候我们可能不需要4个字节来表达一个整型,比如一个人的年龄,一般范围是0岁 - 120岁 左右 ,这时不需要太大的内存,那样只会浪费空间。有些时候我们又需要表达更大的数据,比如表达银河系中的恒星个数,这时可能4个字节的整型都不足以表达。
针对这些特殊情况,我们可以用 short 或者 long 来修饰关键字 int,调整数据范围。比如:
// 经常省略 int ,写成:
// 经常省略 int ,写成:
我们称 a 是一个短整型的变量,它的长度不会比 int 长。称 b 为长整型变量,它的长度不会比 int &短。 大家有没有觉得这段叙述有点怪? 为什么不直接说它们占用多少个字节呢?因为我们也无法确定,C语言标准就是像刚才那么说的,并没有规定它们占用几个字节,具体的情况要根据软硬件平台而定。
但是也是有规律的,一般而言:
char 类型 占用1个字节
short 类型 占用2个字节
long 类型 占用的字节数跟CPU的字长相等
而 int 类型则不一定,比如在字长是64位的CPU平台下,可能是4个字节也可能是8个字节。
现在的问题是:如果我需要在不同的平台下移植我的程序,而且我要求我的变量的大小是固定的,比如4个字节大小,怎么办呢?
办法是,不能直接使用基本数据类型来定义,而是要将它们稍微封装一下,具体如下:比如在A平台中,int 占2字节,long 占4字节。 在B平台中,int 占4字节,long 占8字节。
那如果我要定义一个占用4个字节的整型变量 var , 就不能定义成 &或者 因为这样无法让其同时在A平台中和B平台中长度一致,我们说这样的数据类型是不具可移植性的。那怎么才可以有可移植性呢?
在A 平台中,我们把 int 取个别名,叫做 int16_t, 把 long 也取个别名,叫 int32_t
在B平台中,我们把 int 取个别名,叫做 int32_t ,把 long 也取个别名,叫 int64_t
这样,我们如果想要定义一个长度固定为 4 个字节的整形变量var,我们可以这样定义: int32_ & 这样,不管你将程序放在A平台中还是B平台中,都可以实现长度固定的想法。 至于如何给int 和 long 取别名就很简单了,在A平台中,我们提供这样的代码:
typedef int int16_t;
typedef long int32_t;
在B平台中,我们提供这样的代码:
typedef int int32_t;
typedef long int64_t;
typedef 就是给一种数据类型取别名的,这样,当你的程序需要从一个平台移植到另一个平台时,只需要重新编译就可以了,不需要修改任何代码。
另外,还有一个关键字可以用来修饰整型: unsigned,比如这样定义变量:
上面定义了三个 “无符号” 整型变量a,b和c。这些变量不能表示负数,系统在解释它们的时候,不再将最高位解释成符号位,而是当做最高权值位。
现在来谈谈浮点数,我们可以定义 float 型单精度浮点变量,double 型双精度浮点变量,long double 型长双精度浮点变量。它们可以用来存储带小数的实数。比如:
double f2;
long double f3;
一般而言,它们分别占用4个,8个和12个字节的内存,占用的内存空间越多,能表达的范围和精度越大。具体它们是怎么存储的,精度又怎么确定,请看我的另一篇博客:
, 里面有详细的剖析。
浮点数常量一般有两种表达方式,一种就是最简单的方式,直接写,比如: 3.1415, 或者877.52 等。 另一种就是科学计数法,比如: 前面的 877.52 可以写成 8.7752E2,这的 E2 代表的是10的2次方,同样道理,如果是 4.21E-5, 则表示4.2 乘以 10的 -5 次方。 E可以写成小写的e。
最后一个问题,类型转换的问题。当在一个表达式中出现有不同的数据类型的时候,会有两种结果,第一:类型不兼容,编译出错! 比如,你将一个浮点数跟一个结构体相加,完全牛头不对马嘴,编译直接出错。 第二,类型不同但可兼容,比如 一个整型跟一个浮点型相加,则会将整型临时提升为浮点型,再相加。我们现在来讨论第二种情况。
举个例子:
int a = 100;
double f1 = 3.14;
f2 = a + f1;
代码中,三个变量类型都不相同,但是是兼容的,于是,在执行第5行的时候,系统会将所有的变量临时地提升为它们中精度最高的那种类型,比如在我们这个例子中,f1 是double 类型的,精度最高,因此其他的所有变量都将在这个运算过程中被临时地提升为 double 型参与运算,并最终的结果保存在一个 float 型的变量 f2 中。这么做的原因在于,系统在默认的情况下,只能采取最保守的方法,用最大的代价来保证用户数据在运算的过程中不丢失精度,因为如果你将一个浮点数转化成整型的话,其小数部分就会丢失了。这种系统帮我们自动将“小”类型转换成“大”类型的行为,称为隐式类型转换。
那如果我非要把精度高的数据类型转化成精度低的类型呢? 也可以,那就要显式地指明,比如上面的那个例子:
int a = 100;
double f1 = 3.14;
f2 = a + (int)f1;
在 f1 的前面加了一对圆括号,里面写了一个 int ,表示要在中间的运算过程中强制将 f1 临时降格为 int 类型(这样可能会导致精度的丢失),然后参与运算。 最后要注意,不管是隐式类型转换,还是强制类型转换,转换的都是中间过程中的临时“替身”, 变量本身的类型和值不会发生变化。
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致

我要回帖

更多关于 双精度整型 的文章

 

随机推荐