Very short question but I couldn't find a solution on the web right now.
int test = 1 + 2;
Will 1 + 2
be performed during run- or compile-time?
Reason for asking:
I think most people sometimes use a literal without specifying why it has been used or what it means because they do not want to waste a bit performance by running the calculation and I believe the calculate happens during compiletime and has no effect on performance:
int nbr = 31536000; //What the heck is that?
instead of
int nbr = 365 * 24 * 60 * 60; //I guess you know what nbr is supposed to be now...
Since your examples are essentially constant expressions (i.e. they consist of only constants or constructs that evaluate as such), they will be evaluated at compile time.
A constant-expression is an expression that can be fully evaluated at compile-time.
The type of a constantexpression can be one of the following: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, string, any enumeration type, or the null type.
The following constructs are permitted in constant expressions:
+
, –
, !
, and ~
unary operators.+
, –
, *
, /
, %
, <<
, >>
, &
, |
, ^
, &&
, ||
, ==
, !=
, <
, >
, <=
, and >=
binary operators, provided each operand is of a type listed above.?:
conditional operator.The expression 1 + 2
in int test = 1 + 2
is considered to be a "constant-expression" according to the C# spec:
7.19 Constant expressions
A constant-expression is an expression that can be fully evaluated at compile-time.
In other words: when an expression can be fully evaluated at compile-time, it is considered to be a "constant expression", and those will be evaluated at compile-time.
Kind of a catch-22 when you want to discover the meaning of a constant expression and compile-time evaluation.
To apply the relevant parts of the spec to your example:
A constant expression must be [...] a value with one of the following types: [...] int [...].
Only the following constructs are permitted in constant expressions:
Literals (including the null literal).
[...]
The predefined +, –, *, /, %, <<, >>, &, |, ^, &&, ||, ==, !=, <, >, <=, and >= binary operators, provided each operand is of a type listed above.
[...]
Whenever an expression fulfills the requirements listed above, the expression is evaluated at compile-time.
The last line would be clearer if it would read:
Whenever an expression fulfills the requirements listed above, the expression is [considered to be a constant expression and will be] evaluated at compile-time.
When an expression contradicts any of the listed rules (including things such as using a non-const member invocation or a method call), it will not be considered a constant expression and thus be evaluated at runtime.
Well just tested it with IlSpy
and for code :
private static void Main(string[] args)
{
int value = 365 * 24 * 60 * 60;
Console.WriteLine(value);
}
Compiled MSIL code is :
.....
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
So it does calculate static expression in compile time to improve performance however if we change our code to :
double nbr = Math.Sqrt(365 * 24 * 60 * 60);
Console.WriteLine(nbr);
This time the final result will be populated on run-time because compiler doesn't know value that will be returned by Math.Sqrt()
on compile time.
MsIL code :
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With