赋值表达式
表达式是什么?表达式是由运算符和操作数组成的式子。
如下的代码
#include "iostream.h"
int main()
{
int a=1,b=2,sum;
cout<<(sum=a+b)<<endl;
return 0;
}
那么如下的呢?
#include "iostream.h"
int main()
{
int a=1,b=2;
cout<<(int sum=a+b)<<endl;
return 0;
}
结果是: 编译就会出错!
在这里,这是声明和定义,不能放置于cout输出的位置。
sizeof运算符
C语言中提供了一个可以得到各种数据类型占用内存空间大小的运算符: sizeof运算符。
它的语法如下:sizeof(类型名或变量名)
如下:
#include<iostream>
using namespace std;
int main()
{
cout<<sizeof(int)<<endl;
return 0;
}
在32位机器上就会打印4.
在16位机器上就会打印2.
如果想要得到所有基本类型占用的字节数,如下代码:
#include <iostream>
#include<conio.h>
using namespace std;
int main()
{
cout<<"It will show the lengths of all kinds of numbers(It is system-related):"<<endl;
cout<<"char ---------------"<<sizeof(char)<<endl;
cout<<"bool ---------------"<<sizeof(bool)<<endl<<endl;
cout<<"unsigned char ------"<<sizeof(unsigned char)<<endl;
cout<<"wchar_t ------------"<<sizeof(wchar_t)<<endl;
cout<<"short --------------"<<sizeof(short)<<endl;
cout<<"unsigned short -----"<<sizeof(unsigned short)<<endl<<endl;
cout<<"int ----------------"<<sizeof(int)<<endl;
cout<<"unsigned int -------"<<sizeof(unsigned int)<<endl;
cout<<"long ---------------"<<sizeof(long)<<endl;
cout<<"unsigned long ------"<<sizeof(unsigned long)<<endl;
cout<<"float --------------"<<sizeof(float)<<endl;
cout<<"double -------------"<<sizeof(double)<<endl<<endl;
getch();
return 0;
}
此程序是得到了各种不同的数据类型(或者称作基本数据类型或内置数据类型)在内存中占据的空间。请不要相信这些类型占用空间一定是如上图示,因为它们是具有系统依赖性的,不同的系统可能不一样的。
类型不一致带来的问题
#include "iostream.h"
int main()
{
int i;
cin>>i;
cout<<i<<endl;
return 0;
}
这个程序,声明的i是整型,而实际上如果输入了浮点类型的数,如1.2,那么将打印什么呢?
打印的是1.
原因很简单,声明的int是整型的,当遇到的输入符号不是整数0~9字符时就会认为输入结束。
我们用C风格代码来改写这个程序:
#include<stdio.h>
int main()
{
int i;
scanf("%d",&i);
printf("%d/n",i);
return 0;
}
结果也是一样:
下面是个关于用不同类型的值来赋值的例子:
#include "iostream.h"
int main()
{
int x=10.4;
cout<<x<<endl;
return 0;
}
编译的时候出现如下警告:
意思就是10.4是个double类型常量,现在要把它赋值给整型变量中,可能有数据精度或数值的损失。
A:其实,x的值是在编译结束之前就已经计算出来了。
Q:这个不该是程序执行的时候才算的吗?
A:其实编译器也是一种程序嘛,这些事情编译器可以做了,就不用麻烦CPU在这个程序执行的时候做了。C语言是高效率的程序设计语言,一个很大的原因就在于有很多事情在编译的时候就可以计算好。如下为执行结果:
Q:那么为什么编译器把10.4看成了double类型呢?
A:那你觉得还可以看成什么类型呢?
Q:不可以看成是float类型吗?
A:应该说,float类型只是double类型的子集,编译器也是为了考虑数据精度和数据能表达的范围来考虑,一般对于之类数据都看成double类型统一处理。
A:如下是此源代码用cl编译得到的汇编代码的一部分。
假设此源代码名为 doubleToInt.cpp.
编译命令是: cl /Fa doubleToInt.cpp
源代码如下截图:
生成的部分汇编代码如下:
注意看Line 5处的汇编代码:
就是把整数10赋值给变量x的。
溢出
现在我们深入研究下程序设计语言中存在的溢出现象:
下面这个程序是一个溢出的实例:
#include "iostream.h"
int main()
{
short h=32768;
cout<<h<<endl;
return 0;
}
short类型是16位的,最大能表达的数据是32767,而却给它赋值32768;
这将导致溢出,溢出的结果是可能造成不可预料的错误,一般都会出现错误。
当然溢出也有一定的规律可循:
32767的表示为:
0111 1111 1111 1111
而赋值32768,就是在32767的基础上再加1,得到:
1000 0000 0000 0000,
当然计算机会把这个当作short类型处理,是个负数,-32768.
我们要熟记计算机内部各种数据类型的取值范围,这样才能在应用的时候选择更好的数据类型,而且也能最大程度地避免发生错误;就算发生了错误,也能在最快的时间理解错误可能发生的原因。
【C#的checked关键字】
C#中的checked关键字可以实现对于整型算术运算启用溢出检查。
当然,这个关键字不能直接拿到C语言中来使用,如果可以的话,可以自己写个程序同样用来判断整型数据类型在计算中是否溢出。
【编译器是如何从源代码计算一个整数的值的】
正如上面的代码,short h=32768;
对于编译器来说,源代码就是字符串的集合。如何把数字形式的字符串转换成整数,这是编译器需要做的事情。
C中有atoi、atol等将字符串转换成整数或长整型的函数。
这两个函数在atox.c源文件中有具体实现的代码。
【如何得到一个溢出的数的准确值】
正如上面,当把32768赋给一个short类型的变量时。首先,先考虑short类型的最大和最小值。最大值是32767,最小值是-32768.
再分析,当前赋给此变量的值是多少。
是32768,它和short类型的最大值差不多,而且是比最大值要大。所以,先得到32767的形式。
0111 1111 1111 1111 (中间的空格仅仅是为了看起来更清楚)
32768比32767大1,即再加1.
得到
1000 0000 0000 0000
所以,结果也就知道了。
【用C/C++写的检测溢出程序】
/*++++++
完成时间:2008年8月10日14:51:57
作者: 陈曦
作用概述:此程序用于检测int、short、long类型数据的加法是否发生溢出;运用的是双符号位原理:
如果两个相加的数是符号相同,但是得到的和的符号与它们的不相同,那么这就发生了计算溢出。
程序的局限:如果在输入两个要相加的数的时候,输入的数就已经溢出了,那么程序得到的结果可能就错了。
扩充性:对于float等浮点类型没有进行过测试,不知道此程序是否可以得到正确结果。
++++++*/