Arithmetic operations on literals in C # evaluated at compile time?

A very short question, but I could not find a solution on the Internet right now.

int test = 1 + 2; 

Will 1 + 2 be executed at runtime or compilation?

Reason for request: I think that most people sometimes use literals without indicating why they were used or what it means, because they don’t want to spend a little time doing the calculation, and I believe that the calculation happens at compile time and not affects performance:

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

instead

 int nbr = 365 * 24 * 60 * 60; //I guess you know what nbr is supposed to be now... 
+5
source share
3 answers

Since your examples are essentially constant expressions (i.e. they consist only of constants or constructs that are evaluated 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 the constant expression can be one of the following: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, string, any type of enumeration or null type.

In constant expressions, the following constructions are allowed:

  • Literals (including the null literal).
  • References to constant elements of classes and types.
  • References to members of enumeration types.
  • Parenthesized sub-expressions, which themselves are constant expressions.
  • Cast expressions if the target type is one of the types listed above.
  • The predefined unary operators + , – ! and ~ .
  • Predefined + , – , * , / , % , << , >> , & , | , ^ , && , || , == != , < , > , <= and >= if each operand is of the type specified above.
  • Operator ?: .
+3
source

The expression 1 + 2 in int test = 1 + 2 is considered a "constant expression" according to the C # specification:

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 a "constant expression", and this will be evaluated at compile time.

Kind of catch-22 when you want to know the value of a constant expression and evaluate compile time.

To apply the relevant parts of the specification to your example:

A constant expression must be [...] a value with one of the following types: [...] int [...].

In constant expressions, only the following constructions are allowed:

  • Literals (including the null literal).

  • [...]

  • Predefined +, -, *, /,%, <, β†’, &, |, ^, &, ||, == ,! =, <,>, <=, and> = binary operators if each operand is of the type specified above.

[...]

Whenever an expression fulfills the above requirements, the expression is evaluated at compile time.

The last line would be clearer if she read:

Whenever an expression satisfies the requirements listed above, the expression [is considered a constant expression and will be evaluated at compile time).

If an expression contradicts any of the above rules (including things such as using a non-const member call or method invocation), it will not be considered a constant expression and therefore will be evaluated at runtime.

+3
source

Well, just test it with IlSpy and for the code:

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

Compiled MSIL Code:

 ..... 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 

Therefore, it computes a static expression at compile time to improve performance, but if we change our code to:

 double nbr = Math.Sqrt(365 * 24 * 60 * 60); Console.WriteLine(nbr); 

This time, the final result will be filled at runtime because the compiler does not know the value that Math.Sqrt() will return at 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 
+1
source

Source: https://habr.com/ru/post/1246554/


All Articles