CLR-基元类型以及溢出检查
=========(CLR via C#阅读笔记)========
基元类型(primitive type):
基元类型也不做过多的解释,举个例子即可清晰的辨别
在java里曾使用过Sting s="java"; 定义字符串,然后就会觉得很诧异,为啥是大写开头,我写C#,一直都是 string ,int ,double,float等等小写开头,这时候,来了解基元类型方可解惑。
int a=;
System.Int32 a=;
int a=new int();
System.Int32 a=new System.Int32();
以上定义int类型的语法,都是能正确编译与运行的,其中第一种最方便简洁,那么这种方便简洁的int,string,byte..decimal,object等等都称作C#的基元类型,对应FCL类型则为System.Int32(其它依次类推,注意是大写开头)。
以上,基元类型和FCL类型效果完全一致。
基元类型转换可能造成精度或数量级的丢失:
然后下面谈到,基元类型中的一些转换问题:
int i=; //System.Int32
long j=i; //System.Int64
上述代码能够正确的完成隐式转换,也支持一些字面值的转换。
但是将代码调换一下:
longi=; //System.Int64
int j=i; //System.Int32
这个时候是不安全的转换,因为long 可以容纳更长的数字,如果long对象的值超过了int,那么会发生丢失精度或数量级,这个时候必须使用显示转换。
但是即使做了显示转换,也无法避免误差的产生:
对数据转换造成误差做了一个小小的测试:
得出结论,在超过int(-2,147,483,648 到 2,147,483,647)范围后,int会从头在依次计算,比如比范围多1,就会从最大值回到开头,多2,就会往后再数一个
而浮点型,不论是float还是double都是直接截取整数位不会进行四舍五入(有些语言不是截取)。
checkd和uncheckd基元类操作
作用:
一些元算可能会有溢出发生,例如
byte b=; //无符号八位值,范围0-255
b=(byte)(b+); //溢出得到值 (100+200)-255-1=44
如果,你觉得这种溢出是非法的不可接受的,那么可以加上checked:
几种常见用法:
checked语句对指定的代码块进行检查:
1 //unchecked写法亦然,但是表示不对溢出进行检查
2 checked
3 {
4 byte b=100; //无符号八位值,范围0-255
5 b=(byte)(b+200); //溢出得到值 (100+200)-255-1=44
6 }
需要注意的是,checked操作符仅仅对块里面进行的运算表达式生效,如果你放一个方法进去,是不会有任何效果的。
使用checked操作符:
b=checked((byte)(b+));
b=(byte)checked(b+); //两种写法都可以
这时候,再发生溢出的时候会抛出System.OverflowException: 算术运算导致溢出。
当然在极少数时候,异常是允许的,甚至是希望的,比如:计算哈希值或者校验和。
checked和unchecked到底是啥?
引申:CLR提供了一些特殊的IL指令,允许编译器选择它认为最恰当的行为。CLR有一个add指令,作用是将两个值相加,但不执行溢出的检查。还有一个add.ovf指令,作用也是将两个值相加,但会发生溢出时抛出System.OverflowException,当然减乘除也有对应方法,分别是sub/sub.ovf,mul/mul.ovf和conv/conv.ovf。而上面说到的checked和unchecked则是C#层面上提供的编译器开关,自然用来指定编译器下对应的指令(上面提到的IL指令)。
需要注意的是,使用了/checked+(/check-)编译器开关,会使代码执行变得稍慢,因为CLR会进行对应的语句检查。
如何有效的避免对基元类型的不良操作和编码:
- 尽量使用有符合数值类型,这允许编译器检测更多的上溢/下溢错误(有符号意味着区分正负,无符号是没有负数的),也会减少可能的强制类型转换,另外无符号数值不符合CLS(Common Language Standard)。
- 如果代码可能发生你不希望的溢出(比如错误的输入造成的),就把这些代码放到checked块中,并捕捉异常。
- 将允许溢出的代码块放到unchecked块中
- 没有上述检查操作符的,意味着溢出是bug
- 开发环境最好,打开编译器的/checked+开关(生成-高级),尽可能暴露问题,发布时应使用/checked-开关,确保代码更快的运行(当然如果能够对检查要求严格,又能接受带来的性能损失也可以打开开发来编译,可以防止应用程序在包含已损坏的数据的前提下运行)
特别的地方:
- System.Decimal虽然在C#中是基元类型,但是在CLR中并不是,意味着没有对应的IL指令,它使用int,float,double,uint等数组来表示范围内的大小,如图:
- 可以分析出:1.操作符“+”,“-”...对于decimal其实是无效的,但是我们不仅可以对他进行操作符的基本运算,也可以用提供的Add...等方法进行运算,因为它内部其实是对操作符进行了重载,且在运算不安全时是会自动抛出OverFlowException的异常的。2.checked 和 unchecked无效,它无需cheked操作符来检查抛出异常,也无法unchecked阻止异常抛出。
- System.Numerics.BigInteger类型类似Decimal,也使用数组来表示任意大的数,但是它如何计算都不会溢出,只有在内存不足以改变数组大小时才会抛出异常OutMemoryException。
上述有更为详细的demo,效果如下:
Github地址:
https://github.com/JOJOJOFran/CLR-Via-C--TEST/tree/master/Design_Type/Primitive%20Type
有啥问题欢迎指正!
CLR-基元类型以及溢出检查的更多相关文章
- [CLR via C#]5.1 基元类型
原文:[CLR via C#]5.1 基元类型 某些数据类在开发中非常常用,以至于许多编译器允许代码已简化的语法来操作它们.例如可以使用以下语法来分配一个整数: System.Int32 a = ne ...
- <NET CLR via c# 第4版>笔记 第5章 基元类型、引用类型和值类型
5.1 编程语言的基元类型 c#不管在什么操作系统上运行,int始终映射到System.Int32; long始终映射到System.Int64 可以通过checked/unchecked操作符/语句 ...
- CLR:基元类型、引用类型和值类型
最新更新请访问: http://denghejun.github.io 前言 今天重新看了下关于CLR基元类型的东西,觉得还是有必要将其记录下来,毕竟这是理解CLR成功 之路上的重要一步,希望你也 ...
- checked 和 unchecked 基元类型操作
对基元类型执行的许多算术运算都可能造成溢出: Byte b = ; b = (Byte) (b + ); // b 现在包含 44(或者十六进制值 2C) 重要提示:执行上述算术运算时,第一步要求所有 ...
- CLR via #C读书笔记三:基元类型、引用类型和值类型
1.一些开发人员说应用程序在32位操作系统上运行,int代表32位整数:在64位操作系统上运行,int代表64位整数.这个说法是完全错误的.C#的int始终映射到System.Int32,所以不管在什 ...
- [CLR via C#]基元类型
一.什么是基元类型 某些数据类型如此常用,以至于许多编译器允许代码以简化的语法来操纵它们.例如,可以使用以下语法来分配一个整数: System.Int32 a = new System.Int32() ...
- 重温CLR(四)基元类型、引用类型、值类型
编程语言的基元类型 编译器直接支持的数据类型称为基元类型(primitive type).基元类型直接映射到framework类型(fcl)中存在的类型. 下表列出fcl类型 从另一个角度,可以认为C ...
- 《CLR via C#》读书笔记--基元类型、引用类型和值类型
编程语言的基元类型 编译器直接支持的数据类型称为基元类型.基元类型直接映射到Framework类库中存在的类型.例如:C#中的int直接映射到System.Int32类型.下表给出了C#基元类型与对应 ...
- 《CLR via C#》读书笔记(5)基元类型、引用类型和值类型
5.1 基元类型 编译器直接支持的数据类型称为基元类型(primitive type). 以下4行到吗生成完全相同的IL int a = 0; //最方便的语法 System.Int32 b = 0; ...
- 【CLR Via C#】第5章 基元类型、引用类型、值类型
第二遍看这本书,决定记录一下加深印象. 1,基元类型 什么事基元类型?基元类型是直接映射到FrameWork类库(FCL)中存在的类型,编译器直接支持的数据类型.比如int直接映射到System.In ...
随机推荐
- mysql limit 接收变量
参考文章:https://blog.csdn.net/ljz2009y/article/details/7887743 PREPARE s1 FROM 'SELECT * FROM t LIMIT ? ...
- 【jQuery】 JQ和AJAX
AJAX AJAX全称异步 JavaScript 和 XML(Asynchronous JavaScript and XML),是一种用于网页前端和网站后台进行数据交互的手段.关于AJAX的详细介绍在 ...
- MySQL升级-5.6升级到5.7版本&切换GTID模式
目前未在生产环境中升级过数据库版本,倒是在测试环境跟开发环境升级过. 可以通过mysqldump sql文件进行升级,也可以通过mysql_upgrade升级,前者耗时较长,且 ...
- Mysql性能优化之覆盖索引
因为我们大多数情况下使用的都是Innodb,所以这篇博客主要依据Innodb来讲 b+树(图片来自网络) b+树图来自网络 1.聚集索引与非聚集索引区别 聚集索引:叶子节点包含完整的数据(物理地址连续 ...
- Django--入门篇:下载与项目生成
django作为python web应用开发最火的框架,没有之一,今天就给大家介绍django的一些入门知识. 我们选择pycharm工具,首先得要有django. 1.下载django --pip ...
- C语言程序设计(基础)- 第4周作业
一.PTA作业 完成PTA第四周作业中8个题目,并将其中4个题目的思路列在博客中. 1.7-1 计算分段函数[1] 2.7-2 A除以B 3.7-6 阶梯电价 4.7-7 出租车计价 随笔具体书写内容 ...
- 进程与fork()、wait()、exec函数组
进程与fork().wait().exec函数组 内容简介:本文将引入进程的基本概念:着重学习exec函数组.fork().wait()的用法:最后,我们将基于以上知识编写Linux shell作为练 ...
- 高级软件工程2017第7次作业--C++团队项目:Beta阶段综合报告
1.Beta阶段敏捷冲刺每日报告 Bate版敏捷冲刺报告--day0 Bate版敏捷冲刺每日报告--day1 Bate敏捷冲刺每日报告--day2 Bate敏捷冲刺每日报告--day3 Bate敏捷冲 ...
- DML数据操作语言之常用函数
所谓函数,就是输入某一值,得到相应的输出结果的功能.相当于一个加工厂,给了原料,最终产出成品. 其中原料 就是参数(parameter). 产品 就是返回值. 函数大致可以分为以下五个种类: 算术函数 ...
- nyoj 开方数
开方数 时间限制:500 ms | 内存限制:65535 KB 难度:3 描述 现在给你两个数 n 和 p ,让你求出 p 的开 n 次方. 输入 每组数据包含两个数n和p.当n和p都为0 ...