C# Numeric Casts

Review numeric casts, examining the syntax for casting and the generated IL.
Numeric casts. A numeric cast changes a number's representation. Sometimes numeric casts are necessary in C# programs. Sometimes they are not. We further investigate numeric casts. We show their syntax and their IL.CastsSuffix
Example. First, here we see the basic syntax to cast numbers to different types. This gives us some context for the rest of the article. The view of the program in the debugger is shown above.

And: We see that each new type is converted from the first int and they are strongly typed. These are explicit casts.

Int, uint
C# program that performs explicit casting using System; class Program { static void Main() { // 32-bit integer. int num1 = 1000; // Cast to long. long num2 = (long)num1; // Cast to double. double num3 = (double)num1; // Cast to float. float num4 = (float)num1; // Cast to uint. uint num5 = (uint)num1; // Cast to short. short num6 = (short)num1; // Cast to ushort. ushort num7 = (ushort)num1; // Cast to decimal. decimal num8 = (decimal)num1; // Cast to ulong. ulong num9 = (ulong)num8; } }
Explicit, implicit. Implicit casts are not declared in your code using the parenthesis syntax above. Explicit casts are those you write out in the code. The C# compiler sometimes handles implicit casts the same way as if you used the cast operators.

Tip: Numeric comparisons, such as comparing an int to a long, also cause implicit casts.

Note: In these cases, lots of computations are taking place in our code that we do not see.

Long, int. When you compare a long to an int in an expression, the C# compiler generates extra conv instructions. These add complexity to your code, regardless of performance concerns. It is important to realize this happens.Long

Info: In this example, two conv instructions are generated. There are 12 lines of instructions.

Instructions: The first conv instruction is used to load long value. The second conv instruction is used to compare long to int.

Here: The long's value is loaded with a conv instruction. Then an implicit conversion is done when the two variables are compared.

Note: Numeric types (long, int) always are converted before compared. Sometimes with uint and int no conv instructions are emitted.

C# program that converts long and int using System; class Program { static void Main() { long l = 1000L; int i = 1000; if (l == i) { Console.WriteLine("True"); } } } Intermediate language after compilation: .method private hidebysig static void Main() cil managed { .entrypoint .maxstack 2 .locals init ( [0] int64 l, [1] int32 i) L_0000: ldc.i4 0x3e8 L_0005: conv.i8 L_0006: stloc.0 L_0007: ldc.i4 0x3e8 L_000c: stloc.1 L_000d: ldloc.0 L_000e: ldloc.1 L_000f: conv.i8 L_0010: bne.un.s L_001c L_0012: ldstr "True" L_0017: call void [mscorlib] System.Console::WriteLine(string) L_001c: ret }
Avoid numeric cast. Numeric casts are not always needed. Here we see the same basic code as above, but with no numeric casts in the IL. You can see that the C# code is about the same, but the IL has two fewer instructions.IL

Here: In the example, we removed some casting between long and int and eliminated two conv instructions from being emitted in the IL.

Important: The meaning of the program also changed. It restricts the possible values of the long type.

C# program that avoids casts using System; class Program { static void Main() { int l = 1000; int i = 1000; if (l == i) { Console.WriteLine("True"); } } } Intermediate language after compile: .method private hidebysig static void Main() cil managed { .entrypoint .maxstack 2 .locals init ( [0] int32 l, [1] int32 i) L_0000: ldc.i4 0x3e8 L_0005: stloc.0 L_0006: ldc.i4 0x3e8 L_000b: stloc.1 L_000c: ldloc.0 L_000d: ldloc.1 L_000e: bne.un.s L_001a L_0010: ldstr "True" L_0015: call void [mscorlib] System.Console::WriteLine(string) L_001a: ret }
Safety. Do safe implicit casts cause any harm to programs? Your code is doing things you don't need or want it to do. In a critical application, you don't want uncertainty. For this reason, it is far better to carefully maintain numeric types.

Tip: Most of the time, implicit casts are not worth worrying about—but they are always worth understanding.

File size. File sizes in Windows are reported in longs. Code that casts these values to 32-bit ints is normally safe. These casts, however, are always translated into conv instructions. Exceptions due to invalid casts are also possible.

Also: Sometimes methods specify one integer type, but callers have another integer type. Often it is possible to simply change one method.

Number suffix. Suffixes in the C# programming language refer to the characters such as L or UL on the end of literal numbers. These force the compiler to treat the value as a number of a certain type.

Otherwise: The compiler will use static analysis to try to infer the type of the number, or simply raise a warning.

String, int. To convert or parse a string into an integer, you need to use int.Parse or a similar method. These methods are not considered numeric casts or conversions, but data type conversions. Please see the article on the

Char: In the C# language, char is defined as a Unicode character, not specifically a numeric value type. It follows different rules.

And: You cannot compare a char to an int directly. You can cast the char to an int explicitly.

Operators. The keywords implicit and explicit are used in C# to specify the kinds of casts that are not required, or required, in the compilation process. They define a contract, but don't change runtime behavior.Explicit, Implicit
Checked. The checked keyword is available to prove in your program that the numbers you are using are not overflowing or being truncated in any way. This can improve the correctness of certain algorithms.

Info: Checked provides a way to more easily detect when a number type is not large enough to store the required value.


MaxValue, MinValue: Each numeric type has a maximum and minimum value. Larger types have larger maximums.

Summary. Here we saw examples and notes about numbers such as integers and doubles in the C# language. Overall, C# has performance with numeric types in the same ballpark as C++ and other compiled languages.
Dot Net Perls
© 2007-2020 Sam Allen. Every person is special and unique. Send bug reports to