Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are arithmetic operations on literals in C# evaluated at compile time?

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...
like image 422
Noel Widmer Avatar asked Apr 06 '16 12:04

Noel Widmer


3 Answers

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:

  • Literals (including the null literal).
  • References to const members of class and struct types.
  • References to members of enumeration types.
  • Parenthesized sub-expressions, which are themselves constant expressions.
  • Cast expressions, provided the target type is one of the types listed above.
  • The predefined +, , !, and ~ unary operators.
  • The predefined +, , *, /, %, <<, >>, &, |, ^, &&, ||, ==, !=, <, >, <=, and >= binary operators, provided each operand is of a type listed above.
  • The ?: conditional operator.
like image 57
Rion Williams Avatar answered Nov 14 '22 21:11

Rion Williams


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.

like image 22
CodeCaster Avatar answered Nov 14 '22 22:11

CodeCaster


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
like image 37
Fabjan Avatar answered Nov 14 '22 22:11

Fabjan