当前位置:17727 > 17727.com > 循环者遇到了狼人,运算符和表达式

循环者遇到了狼人,运算符和表达式

文章作者:17727.com 上传时间:2019-12-10

 图片 1

小结,大家要多注意一下C#与C++及C语言中指针及类型的对比。有时不小心,就会引起出错,在检查时,留意查查这方面就是了。

谜题33: 循环者遇到了狼人
    请提供一个对i声明,将下面的循环转变为无限循环。
    while (i != 0 && i == -i)
    {
    }

image.png

在执行完a = a+b后发现a的值变成了-3

思多雅[天行健] 发布时间:2008.11.09
    在前面的几个章节中,我们学习了C#的基本概念,这一章,我们来学习C#的类型与变量。
    C#语言的类型被分为三类:数值类型、引用类型和指针类型。
       type:
           value-type
           reference-type
           poin ter-typ e
    注意:指针类型只能用在不安全代码,我们在后面的章节中会进行专门的讨论。
    数值类型与引用类型所不同的是,数值类型变量直接含有它们的数据,然而引用类型的变量存储对它们的数据的引用,就是后面要介绍的对象。对于引用类型,可能会出现两个变量引用相同对象的情况,这样对于一个变量的的操作就有可能影响到由其它变量引用的对象。对于数值类型,每个变量都有它们自己对数据的拷贝,这样就不可能出现一个对变量的操作影响到另外一个的情况。
    C#的类型系统是统一的,这样任何类型的数据都可以被看做对象。C#中的任何类型都直接或间接地从objiect 类类型派生,而object 是所有类型的最基本类类。引用类型的数值被看做通过对象,这些对象通过把数值看做类型对象来简化。数值类型的数值通过包装和解包操作来被当做对象。

解惑33: 循环者遇到了狼人
    这仍然是一个循环。在布尔表达式(i != 0 && i == -i)中,一元减号操作符作用于i,意味着它的类型必须是数字的:一元减号操作符作用于一个非数字预定义类型操作数是非法的。因此,我们要寻找一个非0的数字类型数值,它等于自己的负值。NaN不能满足这个属性,因为它不等于任何数值,因此,i必须表示一个实际的数字。确定没有任何数字满足这样的属性吗?
    嗯,没有任何实数具有这种属性,但是没有任何一种C#数字类型能够对实数进行完美建模。浮点数值是用一个符号位、一个被通俗地称为尾数(mantissa)的有效数字以及一个指数来表示的。除了0之外,没有任何浮点数等于其符号位取反之后的值,因此,i的类型必然是整数的。
    有符号的整数类型使用2的补码算术运算:为了取得一个数值的负值,要对其每一位取反,然后加1,从而得到结果。2的补码算术运算的一个很大优势是,0具有唯一的表示形式。如果要对int数值0取负值,将得到0xffffffff+1,它仍然是0。但是,这也有一个相应的缺点。总共存在偶数个int数值——准确地说有232个,其中一个用来表示0,剩下奇数个int数值来表示正整数和负整数,这意味着正的和负的int数值的数量必然不相等。换句话说,这暗示着至少有一个int数值,其负值不能正确地表示为int数值。
    事实上,恰恰就有一个这样的int数值,它就是int.MinValue,即-231。它的十六进制表示是0x80000000。其符号位为1,其余所有的位都是0。如果我们对这个值取负值,将得到0x7fffffff+1,也就是0x80000000,即int.MinValue!换句话说,int.MinValue是它自己的负值,long.MinValue也是一样[C#语言规范 7.6.2]。对这两个值取负值将产生溢出,但是C#在整数计算(unchecked上下文)中忽略了溢出。其结果已经阐述清楚了,即使它们并不总是你所期望的。
    下面的声明将使得布尔表达式(i != 0 && i == -i)的计算结果为true,从而使循环无限循环下去:
    int i = int.MinValue;
    下面这个也可以:
    long i = long.MinValue;
    如果你对取模运算很熟悉,那么有必要指出,也可以用代数方法解决这个谜题。C#的int算术运算是实际的算术运算对232取模,因此本谜题需要一个对这种线性全等的非零解决方案:
    i ≡ -i(mod 232)
    在恒等式的两边加i,可以得到:
    2i ≡ 0(mod 232)
    对这种全等的非零解决方案就是i = 231。尽管这个值不能表示成int,但是它和-231是全等的,即与int.MinValue全等。
    总之,C#使用2的补码的算术运算,是不对称的。对于每一种有符号的整数类型(int、long、sbyte和short),负的数值总是比正的数值多一个,这个多出来的值总是这种类型所能表示的最小数值。对int.MinValue取负值不会改变它的值,long.MinValue也是如此。对short.MinValue取负值并将所产生的int数值转型回short,返回的同样是最初的值(short.MinValue)。对sbyte.MinValue来说,也会产生相似的结果。更一般地讲,千万要当心溢出:就像狼人一样,它是个杀手。     对语言设计者的教训与谜题26中的教训一样。考虑对某种不会悄悄发生溢出的整数算术运算形式提供语言级的支持。
    (注:在C#的checked上下文中将进行溢出检查[C#语言规范 7.5.12])

1.C语言数据类型

 图片 2

1.5 浮点类型
C#支持两个浮点类型:float和double。float和double类型用32位单精度和64位双精度IEEE754格式来表示,它提供了一系列数值:
  正零和负零。在大多数情况下,正零和负零与简单的零值相同,但是它们的使用中间有一些区别。
  正无穷大和负无穷大。无穷大是由一个非零成员除以零的操作产生的。例如,1.0/0.0产生正无穷大,而–1.0/0.0产生负无穷大。
  非数字数据,通常缩写为NaN 。NaN 是无效的浮点数操作产生的,例如零除以零。
  形如s × m × 2e  的非零数据有限集,这里s 是1 或者-1,而m 和e 由具体浮点数类型决定:对于float,0 < m < 224  和-149 ≤e ≤ 104,对于double,0 < m < 253  和-1075 ≤e ≤ 970。
float 类型可以代表的数值范围大约从1.5 × 10-45  到3.4 × 1038 ,有7 位数字位精度。
double类型可以代表的数值范围大约从5.0 × 10-324  到1.7 × 10308 ,有15 到16位数字位精度。
如果二元运算符的一个操作数是浮点类型,那么其它操作数必须是整数类型或者是浮点数类型,并且操作按下面求值:
  如果一个操作数是整数类型,那么那个操作数会被转换为与其它操作数一样的浮点数类型。
  如果操作数是double 类型,其它操作数就要转换为double,操作就要按照double 类型的范围和精度来进行,而且计算的结果也是double 类型(对于相关操作,或者是bool)。
  否则,操作至少使用float 的范围和精度,而且计算的结果也是float 类型 (对于相关操作,或者是(bool )。
   
    包括赋值操作符的浮点操作符,从不产生异常。在异常情况下,浮点数操作会产生下面介绍的零、无穷大或NaN 作为替代:
  如果浮点数操作的结果对于目标形式来说太小,操作的结果就会转换为正零或负零。
  如果浮点数操作的结果对于目标形式来说太大,操作的结果就会转换为正无穷大或负无穷大。
  如果浮点数的操作是无效的,操作的结果就会转换为NaN 。
  如果一个或所有浮点操作的操作数都是NaN,那么操作的结果就变为NaN 。
    浮点数操作可以用比操作结果的类型更高的精度来执行。例如,一些硬件结构支持一个比double 类型更大范围和更高精度的“扩展的”或“long double”浮点数类型,并且会隐含地使用这个更高的精度来实现浮点数操作。只有在性能要额外付出时,这样的硬件结构才会被用来实现精度小一些的浮点数操作,而不需要执行同时丧失性能和精度,C#允许所有的浮点数操作使用更高的精度类型。与给出更高精度的结果不同,这样几乎没有任何可测量的影响。在形如x *y/ z 的表达式中,这里的乘法产生一个超出double 类型范围的结果,但是后面的除法带来一个回到double 范围的暂时结果,实际上在大一些的范围形式计算这个表达式会产生有限的结果而不是无穷大。

    C#解惑总目录

图片 3

int a = 29;

int b = 10;

a = a+b;

b = a-b;

a = a-b;

1.2 结构类型
    一个结构类型是一个数值类型,它可以声明构造函数、常数、域、方法、属性、索引、操作符和嵌套类型。结构类型在第11章中描述。

整型变量:变量是CPU为程序开辟的一块内存地址空间的代号,因此其实质存储形式是二进制(即数值是以01代码形式存储在这块内存空间中的,是以补码形式表示的)。一个字节Byte

8bit即8位。补码:正数的补码即为其原码;负数的补码为其原码按位取反,再加1。(所以注意内存溢出的情况)

/#include <stdio.h>
void main()
{
int a, b, c;
a = 32767;
b = a + 1;
printf("%d, %dn", a, b)
}
//输出 32767(0111111111111111), -32768(1000000000000000)
//这里内存溢出了,因为再补码中,最左边第一位表示的是符号位(0表示“+”, 1表 示“-”),当a=32767时即为在16位下所能表示的最大数值,如果再+ 1,则引发内存溢 出,造成0111111111111111 + 1 == 1000000000000000,即为-32768(因为在内存中数值的表示方式为补码,正数的补码即为本身,所以011111111111111 == 32767; 而 1000000000000000表示的是负数,其的反码为 1111111111111111 == (1)111111111111111,所以后15位再+1,即为1000000000000000 == 32768,再算上第一位符号位,即为-32768)

整型的分类:1)基本型:类型说明符为int,占2字节;
2)短整型:类型说明符为short int 或 short,占2字节
3)长整型:类型说明符为long int 或 long, 占4字节
4)无符号整形:类型说明符为unsigned

1.1.2 字符型:字符常量,字符变量,字符串常量。
字符常量定义:用单引号括起来的一个字符(不可以是字符串)。例如:’a’, ‘+’, ‘?’, ‘=’ 都是合法字符常量。
字符常量具有以下特点:1)字符常量只能用单引号括起来,不能用双引号或其他括号;2)字符常量只能是单个字符,不能是字符串;3)字符可以是字符集中的任意字符,但是数字被定义为字符常量后就不能参与数值运算。例,’5’和5是不同的,’5’是字符常量,不可以参与数值运算,但是5仍旧可以。
转义字符:转义字符是一种特殊的字符常量。以反斜杠””开头,后面跟一个或几个字符。转义字符具有特殊的意义, 不同于字符原本的意义。例如,”n”表示回车。(注:这里是使用的双引号,所以它又有别于字符串常量。)目的:用来表示一般字符不便于表示的控制代码。

图片 4

image.png

字符变量定义:字符变量用来存储字符常量,即单个字符。字符变量的类型说明符是char,在函数中定义字符变量即:char a, b;
字符型数据在内存中的存储形式及使用方法:每个字符型变量被分配一个字节的内存空间,因此只能存储一个字符型常量,且该字符型常量是以ASCII码的形式存放在该变量的存储空间中的。例,char a = ’A’; 则a所指代的内存空间中存储的是’A’的ASCII码65的二进制形式01000001。

/#include <stdio.h>
void main()
{
Char a, b;
a = 65;
b = 66;
printf(“%c, %cn”, a, b)
printf(“%d, %dn”, a, b)
}
//输出:A, B
65, 66
//在该例中,a与b是字符型变量,当赋值时赋予整型数据a = 65,b = 66,因此输出时取决于printf函数中要求输出的格式,如要求输出”%c”即字符型时,即按照65, 66的ASCII码输出相对应的字符型常量’A’, ‘B’;如果要求输出”%d”即整型时,即按照原先的赋值输出65,66(注:这里的65,66是整型)。

字符串常量定义:是有一对双引号括起来的字符序列(其长度可以为多个字符也可以是一个字符)。
字符常量与字符串常量的区别:1)字符常量用单引号,字符串常量用双引号;2)字符常量只能是单个字符,字符串常量可以包含一个或多个字符;3)字符常量只占1个字节,而字符串常量占自身字节长度+1,增加的一个字节是为了存放转义字符”O”(字符串结束的标志);4)可以把一个字符常量赋值给字符变量,但是不能把一个字符串常量赋值给字符变量(因为,字符变量仅有1字节的内存空间,而字符串常量往往至少占2个字节,因此会造成内存溢出)。

图片 5

image.png

1.1.3 浮点型:浮点型常量,浮点型变量。(注:在浮点数计算中需要注意舍入误差,因此在不同精度数字计算时需要先将低精度转化为高精度(计算机内部执行),再进行计算)。
浮点型常量只采用十进制。有两种形式:十进制小数形式:由数码0~9和小数点组成;指数形式:由十进制数,加阶码标志“E”或“e”及阶码(阶码必须为十进制整数)组成(合法指数形式为3.11E5 == 3.11 * 10^5 == 311000)。注:浮点型常量可添加后缀,主要根据其类型来添加。
浮点型变量:

图片 6

image.png

浮点型变量分类:1)单精度(float)一般编译器中占4个字节(32位)内存空间(注:根据不同编译器,所占内存字节数可能会有变化),数值范围为3.4E-38 ~ 3.4E38,只能提供7位有效数字;2)双精度(double)占8个字节(64位)内存空间,其数值范围为(1.7E-308 ~ 1.7E308)提供16为有效数字;3)长双精度(long double)

1.2 指针类型:指针是一种特殊的,同时又是具有重要作用的数据类型。 其值用来表示某个变量在内存储器中的地址。虽然指针变量的取值类似于整型量,但是这两个类型是完全不同的量。
1.3 构造类型:构造类型是根据已经定义的一个或多个数据类型用构造的方法来定义的。就是说, 一个构造类型的值可以分解为若干个“成员” 或 “元素”。而每个“成员”都是一个基本类型或者又是一个构造类型。
1.4 空类型:在调用函数值时, 通常应向调用者返回一个函数值。这个返回的函数值时具有一定的数据类型的,应在函数定义及函数说明中给以说明。但是也有一类函数,调用后并不需要向调用者返回函数值, 这种函数可以定义为“空类型”。其类型说明符为void。
1.5 常量与变量:
常量定义:在程序执行过程中,其值不发生改变的量成为常量。
符号常量:用标识符代表一个常量。在使用前必须先定义:#define 标识符 常量

/#define PRICE 30
void main()
{
int num, total;
num = 10;
total = num * PRICE;
printf("total = %d", total);
}

这里的#define 时一条预处理命令,称为宏定义命令,其功能时把该标识符定义为其后的常量值。一经定义,以后在程序中所有出现该标识符的地方均以该常量值代替(#define后面的常量值一改则全改)。注:习惯上符号常量的标识符用大写字母,变量标识符用小写字母。

变量定义:其值可以改变的量成为变量。

图片 7

image.png

这里的“k” 即为变量。注:变量定义必须放在变量使用之前,且一般放在函数体的开头部分。

1.6 各类数值型数据之间的混合运算:
在不同数值类型数据进行混合运算时,需要先把它们的数值类型转换为同一类型,才能进行下一步运算。有两种转换方式:(1)自动转换;(2)强制转换
(1)自动转换:1)若参与运算的数据的类型不同,先转换为同一类型,再运算(在自动转换的情况下,如(1)char a = 'A'; int b =2; printf("%c", a + b); 输出:C。 (2)char a = 'A'; int b =2; printf("%d", a + b); 输出:67。 (3)float a = 2.33; int b =2; printf("%f", a + b); (a,b转换为double类型再相加)输出:4.330000。 (4)float a = 2.33; int b =2; printf("%d", a + b);(编译时会warning,输出错误数字,因为在编译时计算机将a,b自动转换为double类型,然后相加,当要求输出int类型时需要强制转换,否则出错。 (5)long a = 23; int b =2; printf("%d", a + b);(编译时会warning,输出正确数字25, 因为在编译时计算机将a,b自动转换为long int类型,然后相加得到long int类型的25,因此输出int类型仍为25) );2)按照数据长度增加的方向进行转换,以保证精度不降低。例,int和long数据相加时,先把int数据转换成long再进行运算;3)所有的浮点运算都是以双精度进行的,即使所有的元素都是float类型,也都要先转换成double再进行运算(保证数值的最低舍入误差)。4)char和short参与运算时必须先转换为int(注:char型根据其ASCII码进行转换,如果char a = ‘5’,要以5进行运算的话需可以进行自动转换(因为字符’5’对应的ASCII码表中的数值也是5)也可以进行强制转换(直接 a =int(a),得出数字5));5)在赋值运算中,赋值号两边的数据类型不同时,赋值号右边的值的类型转换为赋值号右边的变量的类型。当赋值号右边的数据类型的长度长于左边时,将会按照四舍五入的方式来降低部分精度(即丢失部分数据)。(例:char a = 65; 这里的a是char型,而65是int型,因此要将65转换为其所对应的ASCII码01000001,再转换成对应的字符型'A'然后赋给a)。

图片 8

image.png

//例
/#include <stdio.h>
void main()
{
float PI = 3.14159;
int s, r = 5;
s = r * r * PI;
Printf(“s = %dn”, s)
}
输出:s = 79
计算时,首先PI和r都转换为double,然后相乘,得到的double型数值四舍五入成int型赋给s。

(2)强制转换:转换形式:(类型说明符)(表达式)。 其功能是把表达式的运算结果强制转换成类型说明符所表示的类型。
例,(float) a 将a强制转换成float类型
(int) (x + y) 将x, y强制转换成int(注,这里的x和y都要用括号括起来,因为x,y都要强制转换)
使用强制转换的注意事项:
1)类型说明符和表达式都得加括号(表达式为单个变量可以不加),例如把(int) (x+y)写成(int) (x) + y则变成先把x强制转换成int再与y相加。
2)无论是强制转换还是自动转换,都是临时性的,都不会改变数据说明时对该变量定义的类型(例,int a = 3, b =5; float c; c = (float) (a + b); 然而a和b仍旧是int类型)。

1.7 算术运算符和算术表达式
算数运算符:算数运算符分1)单目运算符;2)双目运算符;3)三目运算符
运算符优先级:

图片 9

image.png

运算符结合性:1)左结合性(自左向右)(如”-”,”+”);2)右结合性(自右向左)(如赋值运算符”=”, x = y = z,即x = (y = z))。

图片 10

image.png

赋值运算的类型转换注意事项:当赋值运算符左右两边类型不同时,系统自动进行类型转换,将右边的类型转换为左边的类型:1)浮点型赋予整型,舍去小数部分; 2)整型赋予浮点型,数值不变,但以浮点型式存放(小数部分的值为0);3)字符型赋予整型,因为字符型为1个字节,而整型为2个字节,因此将字符的ASCII码值放在整型变量的低八位,高八位全为0。整型赋给字符型,只把低八位赋给字符变量(因此一个字符变量存放的int值范围为-128~256,这里需要注意的是最左边第一位为符号位,当输入负值时,其它位求反再加1得补码(其实经过实际测试,当输入为正数时,但是输入值超过127时,printf("%d", a)输出的是一个负值,因为127 == 01111111,而128 == 100000000(编译器自动认为是负数),即(1)0000000求反(1)1111111,再+1得(1)10000000 == - 128))。
再赋值运算符”=”之前加上其他二目运算符可以构成复合运算符,如 +=, -=, *=, /=, %=, <<=, >>=, &=, ^=, !=等。

逗号运算符 “,”, 功能是把两个表达式连接起来组成一个表达式。
一般形式是:表达式1, 表达式2;
其求值过程是,分别求出2个表达式的值,然后以表达式2的值作为整个逗号表达式的值(扩展到表达式n,则表达式n的值即为整个逗号表达式的值)。

//例
/#include <stdio.h>
void main()
{
int a = 2, b = 3, c = 4, x, y;
y = (x = a + b), b + c;
printf(“y = %d, x = %d”, y, x);
}
//输出:y = 7, x = 5

 图片 11

-------思多雅[天行健]版权所有,首发太平洋论论坛,转载请注明-------

1.1 基本类型:其值不可以再分解为其他类型
1.1.1 整型:整型常量,整型变量。
整型常量:有3种形式:十进制(没有前缀,数码为0~9),八进制(以0为前缀,数码取值为0 ~ 7),十六进制(以0X或0x为前缀,数码取值为0 ~ 9和A - F(a ~ f))。注:整型常量可添加后缀,主要根据其类型来添加。

 

4.1.8 枚举类型
枚举类型是一种有名称常数的独特类型。每个枚举类型都有前级类型,可以是byte、short、int或long。枚举类型通过枚举声明来定义。

 

1.4 整数类型
    C#支持九种整数类型:sbyte、byte、short、ushort、int、uint、long、ulong和char。这些整数类型有下面的大小和数值范围:
  sbyte类型表示有符号的8位整数,数值范围为-128到127。
  byte类型表示无符号8 位整数,数值范围为0 到255。
  short类型表示有符号16位整数,数值范围为-32768 到32767。
  ushort类型表示无符号16位整数,数值范围为0 到65535。
  int类型表示有符号32 位整数,数值范围为–2147483648 到2147483647。
  uint类型表示无符号32 位整数,数值范围为0 到4294967295。
  long类型表示有符号64 位整数,数值范围为–9223372036854775808 到9223372036854775807。
  ulong类型表示无符号64 位整数,数值范围为0 到18446744073709551615。
  char类型表示无符号16位整数,数值范围为0 到65535。char类型的可能数值集符合Unicode字符集。
整数类型一元和二元操作符总是按有符号32 位精度、无符号32 位精度、有符号64 位精度或无符号64位精度进行操作。
  对于一元+和~操作符,操作数被转换为类型T,这里T 是int、uint、long 和ulong 中第一个可以完全代表操作数的所有可能值的类型。操作使用类型T 的精度来实现,而结果的精度也是T。
  对于一元操作符-,操作数被转换为类型T,这里T 是int 和long 中第一个可以完全代表操作数的所有可能值的类型。操作使用类型T 的精度来实现,而结果的精度也是T。一元操作符-不能应用于ulong 类型操作数。
  对于二元操作符+、–、*、/、%、&、^、|、==、!=、>、<、>=和<=操作符,操作数被转换为类型T,这里T 是int、uint、long 和ulong 中第一个可以完全代表操作数的所有可能值的类型。操作使用类型T 的精度来实现,而结果的精度也是T (或相关操作符bool )。
  对于二元操作符<<和>>操作符,操作数被转换为类型T,这里T 是int、uint、long 和ulong 中第一个可以完全代表操作数的所有可能值的类型。操作使用类型T 的精度来实现,而结果的精度也是T

而后面两步计算均能得出正确的结果….

1.7 布尔类型
    bool类型表示布尔逻辑量,bool类型的可能值为true和false。
    在bool 和其它类型间不存在标准的转换。特别是,bool 类型与整数类型截然不同,bool 数据不能用于使用整数类型的地方,反之亦然。
    在C 和C++语言中,零整数值或空指针可以被转换为布尔数值false,而非零整数数值或非空指针可以转换为布尔数值true 。但在C#中,这样的转换由显式地把整数数值和零比较或显式地把对象和null 比较来实现。

我们知道有一个int.MaxValue和int.MinValue表示int型的最大值和最小值。

1.6 十进制类型
    十进制类型是一个128位数据类型,适合金融和货币计算。十进制类型可以代表的数值范围是从      -28          28
1.0 × 10 到大约7.9 × 10 ,有28 到29 个有效数字位。 e ,这里s 是1 或者-1,0 ≤m < 296 而-28 ≤e ≤ 0 。
十进制
十进制类型数值的有限集合形式为s × m × 10
类型不支持有符号零、无穷大和NaN 。
    一个十进制数由96 位整数和十位幂表示。对于一个绝对数值小于1.0m 的十进制数,数据就是第28 个十进制位,但是没有更多。对于绝对值大于或等于1.0m 的十进制数,数据可能是28 或29 数字位。与float 和double 类型相比,如0.1 的十进制小数成员可以就用十进制表示。在用float 和double 表示时,这样的成员经常为无穷小数,使得这些表示有更大的舍入误差。
     如果一个二元操作符的操作数是十进制类型,其它操作数也必须是整数类型或十进制类型。如果要使用一个整数类型操作数,在操作被执行前它会被转换为十进制数。
    十进制类型的数值的操作就是28 或29 数字位,但是不会多于28 十进制位。结果为最接近的可表示的数值,当结果与两个可表示数值都距离都相等时,选择在最小数据位上为奇数的数值。
    如果十进制算术操作产生了一个在舍入后对于十进制形式太小的数据,操作的结果就变为零。如果一个十进制算术操作产生了一个对于十进制形式太大的数据,就会抛出一个OverflowException错误。
    十进制类型比浮点类型有更高的精度但是有更小的范围。这样,从浮点数类型转换到十进制类型也许会产生溢出的异常,并且从十进制类型转换到浮点数类型也许会有精度损失。出于这些原因,不存在浮点数类型和十进制类型间的隐式转换,并且也没有显式的情况,在同一个表达式中把浮点数和十进制操作数混合在一起是不可能的。

算术溢出

算术运算符(+、-、*、/)的计算结果可能会超出所涉数值类型的可取值范围。 详细信息应参考特定运算符的相关章节,而一般情况下:

  • 整数算术溢出或者引发 OverflowException,或者放弃结果的最高有效位。 整数被零除总是引发 @System.DivideByZeroException。

发生整数溢出时,具体影响视执行上下文而定,上下文可为 checked 或 unchecked。 在 checked 上下文中引发 OverflowException。 在 unchecked 上下文中,放弃结果的最高有效位并继续执行。 因此,C# 让你有机会选择处理或忽略溢出。 默认情况下,算术运算发生在 unchecked 上下文中。

除算术运算以外,整型类型之间的显式转换也会导致溢出(例如,将 long 显式转换成 int),并受到 checked 或 unchecked 执行的约束。 但是,位运算符和移位运算符永远不会导致溢出。

  • 浮点算术溢出或被零除从不引发异常,因为浮点类型基于 IEEE 754,因此可以表示无穷大和 NaN(非数值)。
  • 小数算术溢出总是引发 OverflowException。 小数被零除总是引发 DivideByZeroException。

 

 

总结:大多数情况下数值计算很少有机会碰到溢出,但具体特殊场景应具体对待。

如:

1,  变量初始化时给定为int.MaxValue,在使用时一定要考虑计算溢出。

2,  在大量的循环或递归中计算时有可能会导致算术溢出。

3,  从IO输入设备中取值,尤其是用户输入的值中很有可能是一个溢出的无效输入。

4,  注意.NET CLR默认情况下算术运行是发生在unchecked上下文。如果发生算术溢出,程序不会出错,可能得到正确或错误的结果。

 

 

 

-------思多雅[天行健]版权所有,首发太平洋论论坛,转载请注明-------

 

1.3 简单类型
    C#提供了一系列的预定义结构类型,称为简单类型。这些简单类型通过关键词确定,但是这些关键词可以为在System 名称空间中的预定义结构类型关键词起简单的别名,就像下面表中所示。
   关键字                有别名的类型
   sbyte              System.SByte
   byte               System.Byte
   short              System.Int16
   ushort             System.Uint16
   int                System.Int32
   uint               System.Uint32
   long               System.Int64
   ulong              System.Uint64
   char               System.Char
   float              System.Single
   double             System.Double
   bool               System.Boolean
   decimal            System.Decimal
    一个简单类型和它有别名的结构类型是不可分辨的。换句话说,当写下保留字byte 时和写System.Byte确实没有什么区别,并且用System.Int32 也与用保留字int 相同。
    因为一个简单类型代表了一个结构类型,所以每个简单类型都有成员。例如,int 有在System.Int32 中声明的成员和从System.Object 中继承的成员,并且下面的语句是允许的:
      int i = int.MaxValue;           // System.Int32.MaxValue constant
      string s = i.ToString();        // System.Int32.ToString() instance method
      string t = 123.ToString();      // System.Int32.ToString() instance method
    注意,整数文字上是int 类型数据,并且同时也是System.Int32 结构类型的数据。
简单类型与其它结构类型,其它结构类型允许包含附加操作符:
  大多数简单类型允许通过使用文字来创建 (§错误!未找到引用源。)。例如,123 是int 类型量,而'a'是字符类型量。C#使得不用对其它结构类型文字进行预定义,而其它结构类型数据基本上是通过那些结构类型的构造函数来创建。
  当一个表达式的运算符都是简单类型常数时,编译器在编译时就可以对这个表达式进行赋值。这样一个表达式称为常数表达式(§错误!未找到引用源。)。包括其它结构类型定义的操作符的表达式通常意味着运行时赋值。
  通过const 声明,就有可能声明一个简单类型(§10.3)的常数。不可能有其它结构类型的常数,但是static readonly 域提供了相似的作用。
  包括简单类型的转换可以参加由其它结构类型定义的转换操作符的赋值,但是用户定义的转换操作符不能参与另外一个用户定义操作符的赋值。

 

char 类型被分类为一种整数类型,但是它在两点上不同于其它整数类型:
  没有从其它类型到字符类型的隐含的转换。甚至,即使sbyte、byte和ushort类型的数据完全可以用char类型代表,但是从sbyte、byte和ushort类型到char 的隐含转换也不存在。
*  char 类型的常数必须写成字符文字。字符常量可以只是写成与一个斜杠结合的整数文字。例如,(char)10与'x000A'相同。
    checked和unchecked操作符和语句用来控制检查整数类型算术操作和转换(§7.5.13)的溢出。在一段checked上下文中,一个溢出产生一个编译时错误或者引起扔出一个OverflowException。在一段unchecked 的上下文里,溢出被忽略并且不需要送到目标类型的任何高端位被丢弃。

相信大家很容易写出来,但考虑到边界值情况时会有一些有趣的事情。

一、C#的数值类型
    数值类型既是一个结构类型也是枚举类型。C#提供了一系列预定义结构类型,称为简单类型。简单类型通过保留字指定,并且进一步分成数字类型,整数类型和浮点数类型。
       value-type :
           struct-typ e
           enum-type
       struct-typ e:
           type-name
           simp le-type
       simp le-type :
           numeric-type
           bool
       numeric-type :
           integral-type
           floa ting-point-type
           decimal
       integral-type :
           sbyte
           byte
           short
           ushort
           int
           uint
           long
           ulong
           char
      floa ting-point-type:
         float
         double
      enum-type :
         type-name
    所有数值类型都隐式地从类object 继承。不允许任何类型从数值类型派生,因而数值类型是被默认封闭的。
    一个数值类型的变量通常包含一个那种类型的数值。不像引用类型,数值类型的数值不能为null 或是引用一个进一步派生类型的变量。
    对某个数值类型的变量赋值就会创建一个对所赋数值的拷贝,它复制了引用而不是引用所指定的对象。

 

1.1 默认构造函数
    所有类型都隐含地声明了一个公共的无参数的构造函数,称为默认构造函数。默认构造函数返回一个初始值为零的实例,为数值类型的默认数值:
  对于所有单独类型,默认数值是由一个零位格式产生的数值:
  对于sbyte、byte、short、ushort、int、uint、long和ulong,默认的数值为0。
  对于char,默认的数值为'x0000'。
  对于float,默认的数值是0.0f。
  对于double,默认的数值为0.0d。
  对于decimal,默认的数值为0.0m。
  对于bool,默认的数值为false。
  对于一个枚举类型E,默认数值是0。
  对于结构类型,默认数值是把所有数值类型域设为它们的默认类型并且把所有引用类型域设为null的数值。
    像其它任何构造函数一样,一个数值类型的默认的构造函数用new 操作符调用。在下面的例子中,变量i 和j 都初始化为0。
      class A
      {
         void F() {
            int i = 0;
            int j = new int();
          }
      }
    如上所示,因为每个数值类型隐含的都有公共无参数构造函数,所以让一个结构类型包含一个外部声明的无参数构造函数是不可能的。一个结构类型可以允许声明一个参数化的构造函数。例如
      struct Point
      {
         int x, y;
public Point(int x, int y) {
             this.x = x;
             this.y = y;
           }
       }
    如果已经给出上面的声明,那么语句
       Point p1 = new Point();
       Point p2 = new Point(0, 0);
    都会创建一个Point,其中x 和y 被初始化为0。

但下面申明的变量a,b进行相加时可以肯定的是出现了算术溢出错误,但却依然可以得到正确的结果。

在申明x变量时程序编译会报错。

解释:参考msdn操作符说明:

操作符重载和隐式转换:

 图片 12

 

使用中间变量交换两个int型变量的值:

当我们直接定义:int a = int.MaxValue + 1的时候,编译器会提示出错:

 

 

本文由17727发布于17727.com,转载请注明出处:循环者遇到了狼人,运算符和表达式

关键词: