4

When we declare a variable of int for example:

int i = 4;

The following IL is generated :

IL_0001:  /* 1A   |                  */ ldc.i4.4

I can understand that 1A is the hexadecimal representation of 4, so am i understanding right that hexadecimal value is saved used to refer to value of it or it means something different?

When i declare a double variable like:

double d = 12.34;

Following IL is generated which i am not able to get few things in it:

IL_0003:  /* 23   | AE47E17A14AE2840 */ ldc.r8     12.34

How is 23 coming and what it means and what is AE47E17A14AE2840 here?

When i declare a float with same value:

float f = 12.34f;

i have this IL now:

IL_000d:  /* 22   | A4704541         */ ldc.r4     12.34

Same question here as well how 22 comes and what it means and what is A4704541 ?

Ehsan Sajjad
  • 61,834
  • 16
  • 105
  • 160
  • These are just comments. They do not impact the binary at all. your disassembler generates them. – usr Jan 21 '16 at 12:38

3 Answers3

10

I think it is important to understand what ildasm is telling you. The bytes in front of the pipe character are the values of the opcode and the following bytes are the operand or parameter.

I can understand that 1A is the hexadecimal representation of 4, so am I understanding right that hexadecimal value is saved used to refer to value of it or it means something different?

1A in this case is the value of the ldc.i4.4 opcode. This opcode is a shortcut of a ldc.i4 4 instruction which would result in the absolute same behavior, but would be 5 bytes long, 1 byte opcode and 4 bytes parameter. These shortcuts exists for the int values from -1 to 8 because they are often used and so the size of the method body can be reduced.

Now it should be clear how your floating point instructions are formed. 23 and 22 are the opcodes and the parameter is the IEEE 754 encoded floating point number.

thehennyy
  • 4,020
  • 1
  • 22
  • 31
9

Different IL instructions have different byte codes. ldc.i4.4 is 0x1A, ldc.r8 is 0x23, ldc.r4 is 0x22. The decompiler converted these byte values to their corresponding IL instruction string, helping you to read the code.

The ldc.r4 and ldc.r8 instruction have extra bytes to encode the argument, respectively a 4 byte float and an 8 byte double. The decompiler shows the byte representation for the values. A4-70-45-41 are the same bytes you get from BitConverter.GetBytes(12.34f), just try it in a small program to see that for yourself.

The ldc.i4.4 instruction is a bit special, it is a dedicated instruction that pushes 4 and has no argument. Integer values of -1 through 9 have such an instruction, they are very common in a program. Giving them dedicated instructions keeps the IL compact.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
5

"AE 47 E1 7A 14 AE 28 40" is the hexadecimal representation of the actual bytes representation of the double value 12.34.

To prove that

double d = 12.34;   
var bytes = BitConverter.GetBytes(d);
StringBuilder sb = new StringBuilder();
foreach (var b in bytes)
{
    sb.Append(b.ToString("X2"));
}
sb.Dump();

Prints

AE47E17A14AE2840

23 is the hexadecimal representation of the Opcode value ldc.r8 and 22 for ldc.r4 etc.

Source

Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189