是否在编译时对C#中的文字进行了算术运算?

时间:2016-04-06 12:48:09

标签: c# performance literals

非常简短的问题,但我现在无法在网上找到解决方案。

dragonfly_accessor :avatar do
      default  Rails.root.join('public', 'images', 'default', 'avatar.png')    
    end

在运行或编译时会执行int test = 1 + 2; 吗?

询问理由: 我认为大多数人有时使用文字而没有说明为什么使用它或它意味着什么,因为他们不想通过运行计算浪费一点性能,我相信计算在编译期间发生并且对性能没有影响:

1 + 2

而不是

int nbr = 31536000; //What the heck is that?

3 个答案:

答案 0 :(得分:3)

由于您的示例基本上是常量表达式(即它们仅由常量或构造进行评估),因此它们将be evaluated at compile time

  

一个常量表达式是一个可以完全评估的表达式   编译时间。

     

constantexpression的类型可以是以下之一:sbyte,byte,short,ushort,   int,uint,long,ulong,char,float,double,decimal,bool,string,   任何枚举类型或null类型。

在常量表达式中允许使用以下结构:

  • 文字(包括空文字)。
  • 引用类和结构类型的const成员。
  • 引用枚举类型的成员。
  • 带括号的子表达式,它们本身就是常量表达式。
  • 投射表达式,前提是目标类型是上面列出的类型之一。
  • 预定义的+!~一元运营商。
  • 预定义的+*/%<<>>,{{1 }},&|^&&||==!=<><=二元运算符,前提是每个操作数都是上面列出的类型。
  • >=条件运算符。

答案 1 :(得分:3)

根据C#规范,1 + 2中的int test = 1 + 2表达式被视为“常量表达式”:

  

7.19常量表达式

     

constant-expression是一个可以在编译时完全评估的表达式。

换句话说:当一个表达式可以在编译时被完全评估时,它被认为是一个“常量表达式”,那些进行评估编译时间。

当你想要发现常量表达式和编译时评估的含义时,有点像catch-22。

要将规范的相关部分应用于您的示例:

  

常量表达式必须是具有以下类型之一的值:[...] int [...]。

     

在常量表达式中只允许使用以下结构:

     
      
  • 文字(包括空文字)。

  •   
  • [...]

  •   
  • 预定义的+, - ,*,/,%,&lt;&lt;,&gt;&gt;,&amp;,|,^,&amp;&amp;,||,==,!=,&lt ;,&gt;,&lt; =和&gt; =二元运算符,前提是每个操作数都是上面列出的类型。

  •   
     

[...]

     

只要表达式满足上面列出的要求,就会在编译时计算表达式。

如果读到的话,最后一行会更清楚:

  

每当表达式满足上面列出的要求时,表达式 [被认为是一个常量表达式,并且将在编译时进行评估。

当表达式与任何列出的规则(包括使用非const成员调用或方法调用等)相矛盾时,它不会被视为常量表达式,因此在运行时进行评估。

答案 2 :(得分:1)

刚刚使用IlSpy和代码

进行了测试
private static void Main(string[] args)
{
    int value = 365 * 24 * 60 * 60;
    Console.WriteLine(value);
}

编译的MSIL代码是:

.....

IL_0000: nop
IL_0001: ldc.i4 31536000       // its calculated already
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: call void [mscorlib]System.Console::WriteLine(int32)
IL_000d: nop
IL_000e: ret
} // end of method Program::Main

因此,如果我们将代码更改为:

,它会在编译时计算静态表达式以提高性能
double nbr = Math.Sqrt(365 * 24 * 60 * 60);

Console.WriteLine(nbr);

这次最终结果将在运行时填充,因为编译器不知道Math.Sqrt()在编译时返回的值。

MsIL代码:

IL_0000: nop
IL_0001: ldc.r8 31536000
IL_000a: call float64 [mscorlib]System.Math::Sqrt(float64)
IL_000f: stloc.0
IL_0010: ldloc.0
IL_0011: call void [mscorlib]System.Console::WriteLine(float64)
IL_0016: nop
IL_0017: ret
} // end of method Program::Main