Ari*_*tos 40 c# compiler-construction nullable
当我比较可空的短值时,编译器首先将它们转换为整数以与null进行比较.例如,考虑这个简单的代码:
short? cTestA;
if (cTestA == null) { ... }
Run Code Online (Sandbox Code Playgroud)
它由编译器转换为:
short? CS$0$0001 = cTestA;
int? CS$0$0002 = CS$0$0001.HasValue ? new int?(CS$0$0001.GetValueOrDefault()) : null;
if (!CS$0$0002.HasValue){ ... }
Run Code Online (Sandbox Code Playgroud)
这适用于包括.NET 4在内的所有.NET版本.
我在这里错过了什么?仅针对HasValue检查进行双重转换的原因是什么?
我期望编译器做的是使用.HasValue进行简单的检查if (cTestA.HasValue){}.至少这是我在发现此转换后在代码中执行的操作.
为什么所有这些额外的代码都添加了这么简单的测试?
Eri*_*ert 37
回复:你的最新更新:
这是可空算术优化器中的错误.
int?当您执行以下操作时,可空的优化器将删除不必要的转换:
short? s = null;
int? x = s + 1;
Run Code Online (Sandbox Code Playgroud)
未优化的codegen相当于:
short? s = null;
int? x;
int? temp = s.HasValue ? new int?((int)s.Value) : new int?();
x = temp.HasValue ? new int?(x.Value + 1) : new int?();
Run Code Online (Sandbox Code Playgroud)
优化的codegen相当于:
short? s = null;
int? x;
x = s.HasValue ? new int?((int)s.Value + 1) : new int?();
Run Code Online (Sandbox Code Playgroud)
但是,优化器包含一个错误; 我们不会删除不必要的转换以获得相等.
谢谢你引起我的注意; 我们将为Roslyn修复它.我实际上是要在接下来的几周内为Roslyn编写可空的优化器.
更新:我确实写了优化器,如果你对它的工作原理感兴趣,我写了一系列文章,从这里开始:
http://ericlippert.com/2012/12/20/nullable-micro-optimizations-part-one/
Ant*_*ram 29
请参阅C#4.0语言规范的 4.1.5节.特别感兴趣的是:
C#支持九种整数类型:sbyte,byte,short,ushort,int,uint,long,ulong和char.[省略文字]
积分型一元和二元运算符始终以带符号的32位精度,无符号32位精度,带符号的64位精度或无符号64位精度运行:
[省略要点]
对于二进制+, - ,*,/,%,&,^,|,==,!=,>,<,> =和<=运算符,操作数转换为类型T,其中T是第一个int,uint,long和ulong,可以完全表示两个操作数的所有可能值.然后使用类型T的精度执行操作,结果的类型是T(或关系运算符的bool).不允许一个操作数为long类型,另一个操作数为binary类型的二元运算符.
使用short的操作被提升为int,并且这些操作被提升为可以为空的对应物.(这导致7.3.6.2和7.3.7节)
好吧,这是设计,但仍然不明白为什么他们这样做,他们已经优化了字符串添加太多,为什么单独留下数字并为这个简单的比较添加更多的代码
这就是语言设计的方式,同时考虑到现代建筑的优化.未进行具体在这方面,但考虑埃里克利珀的话作为陈述这里
算术永远不会在C#中做空.算术可以用ints,uints,longs和ulongs来完成,但算术永远不会在短时间内完成.短程提升为int,算术以整数形式完成,因为正如我之前所说,绝大多数算术计算都适合于int.绝大多数都不适合做空.在针对整数优化的现代硬件上,短算术可能较慢,而短算术不会占用更少的空间; 它将在芯片上以整数或多头完成.
您的最新更新:
我希望编译器做的是使用.HasValue进行简单检查if(cTestA.HasValue){}至少这是我在发现此转换后对代码所做的操作.所以这就是我真的不明白为什么不做那么简单的想法,而是添加所有这些额外的代码.编译器总是尝试优化代码 - 为什么在这里避免使用简单的.HasValue检查.我肯定在这里遗漏了一些东西......
我将不得不推迟编译专家说出他们为什么选择转换而不是立即进行HasValue检查,除非说可能只是一个操作顺序.语言规范说二进制运算符操作数被提升,这就是他们在提供的代码片段中所做的.语言规范接着后来说,检查x == null,其中x是可以为空的值类型,可以转换为!x.HasValue,这也是他们所做的.在您提供的已编译代码中,数字促销只是先于可空行为.
至于编译器总是试图优化代码,专家可以再次澄清,但事实并非如此.它可以进行优化,而其他可能会延迟抖动.根据是否是调试与发布版本,无论是否附加调试器,都可以对编译器或抖动进行优化,也可以不进行优化.毫无疑问,他们可以做出优化,他们只是选择不这样做,因为成本与收益并没有发挥作用.