Primitive types and implicit conversions

D

Dennis Myrén

Hi.

Just some questions regarding unsigned (well, signed as well) primitive
types.

uint u = 123;

From MSDN:
"When an integer literal has no suffix, its type is the first of these types
in which its value can be represented: int, uint, long, ulong."

So, this means writing uint u = 123; means i first create an int
and then implicitly cast it to uint?
Then, the above statement would result in twice the overhead
as just using an int, is that right?
A suffix may also be applied to the uint creation statement above:
uint u = 123U;
If i use the suffix of 'U', am i then working around the implicit conversion
which is taking place?

Finally, as we know, a suffix cannot be applied to ushort instances:
ushort u = 123U; // Compilation error.
So, is it so, that when assigning a value to ushort, an implicit conversion
from
int is *always* performed?
Then, instantiating a ushort instance(which should be more efficient than
int),
is actually more overhead than instantiating an int,
allocating sizeof(ushort) + sizeof(int) = 6 bytes rather than sizeof(ushort)
= 2?

Or maybe the compiler is helping us to optimize this?
 
J

Jon Skeet [C# MVP]

Dennis Myrén said:
Just some questions regarding unsigned (well, signed as well) primitive
types.

uint u = 123;

From MSDN:
"When an integer literal has no suffix, its type is the first of these types
in which its value can be represented: int, uint, long, ulong."

So, this means writing uint u = 123; means i first create an int
and then implicitly cast it to uint?

No, I believe what happens is that the literal is just checked at
compile time and the type of the field is set to uint, but the same
initialization code is used for both signed and unsigned values.
Then, the above statement would result in twice the overhead
as just using an int, is that right?
No.

A suffix may also be applied to the uint creation statement above:
uint u = 123U;
If i use the suffix of 'U', am i then working around the implicit conversion
which is taking place?

Nothing's done at runtime - there's nothing to work round.
Finally, as we know, a suffix cannot be applied to ushort instances:
ushort u = 123U; // Compilation error.
So, is it so, that when assigning a value to ushort, an implicit conversion
from
int is *always* performed?
Then, instantiating a ushort instance(which should be more efficient than
int),
is actually more overhead than instantiating an int,
allocating sizeof(ushort) + sizeof(int) = 6 bytes rather than sizeof(ushort)
= 2?

No, because that doesn't happen. Look at the IL generated
Or maybe the compiler is helping us to optimize this?

Sort of.

Look at the results of a few things in ILDASM - that will help you.
 
D

Dennis Myrén

OK. Thank you Jon.
Lately, i have had a bad feeling because i have used a lot of unsigned types
and could not stop thinking about this.

Jon Skeet said:
Look at the results of a few things in ILDASM - that will help you.
Yes, that is a good idea.
I should begin studying the IL that is generated from my code.

--
Regards,
Dennis JD Myrén
Oslo Kodebureau
Dennis Myrén said:
Just some questions regarding unsigned (well, signed as well) primitive
types.

uint u = 123;

From MSDN:
"When an integer literal has no suffix, its type is the first of these
types
in which its value can be represented: int, uint, long, ulong."

So, this means writing uint u = 123; means i first create an int
and then implicitly cast it to uint?

No, I believe what happens is that the literal is just checked at
compile time and the type of the field is set to uint, but the same
initialization code is used for both signed and unsigned values.
Then, the above statement would result in twice the overhead
as just using an int, is that right?
No.

A suffix may also be applied to the uint creation statement above:
uint u = 123U;
If i use the suffix of 'U', am i then working around the implicit
conversion
which is taking place?

Nothing's done at runtime - there's nothing to work round.
Finally, as we know, a suffix cannot be applied to ushort instances:
ushort u = 123U; // Compilation error.
So, is it so, that when assigning a value to ushort, an implicit
conversion
from
int is *always* performed?
Then, instantiating a ushort instance(which should be more efficient than
int),
is actually more overhead than instantiating an int,
allocating sizeof(ushort) + sizeof(int) = 6 bytes rather than
sizeof(ushort)
= 2?

No, because that doesn't happen. Look at the IL generated
Or maybe the compiler is helping us to optimize this?

Sort of.

Look at the results of a few things in ILDASM - that will help you.
 
D

Daniel O'Connell [C# MVP]

Dennis Myren said:
Hi.

Just some questions regarding unsigned (well, signed as well) primitive
types.

uint u = 123;

From MSDN:
"When an integer literal has no suffix, its type is the first of these
types
in which its value can be represented: int, uint, long, ulong."

So, this means writing uint u = 123; means i first create an int
and then implicitly cast it to uint?

That quote basically means that the expression "123" is typed as int.
123.GetType() will resolve to the same thing as typeof(System.Int32) and
Convert.ToInt64(123) calls theConvert.ToInt64(int) while 123u.GetType()
returns typeof(System.UInt32) and calls the Convert.ToInt64(uint) overload.
This is strictly a language convention and is not mapped into the actual
..NET runtime.

The actual value will be loaded with the instruction sequence
ldc.i4 0x9b
stloc.0

which is identical to the instruction sequence generated for int u = 123 or
ushort u = 123.
However, ulong u = 123 generates a slightly different sequence:
ldc.i4 0x9b
conv.i8
stloc.0

This is fundamentally the same as
ldc.i4 0x0
ldc.i4 0x9b //note I may have the loads backwards here, I tend to use
conv.i8
//when I'm using MSIL
stloc.0

Which the VB compiler favors, I believe. This is done primiarly because
stloc.0 into a ulong expects 8 bytes while there are only 4 bytes on the
stack.

The sum total, however, is that the MSIL and the C# spec aren't always a
good representation of what will actually occur. IIRC, the VB and C# style
ulong loads end up generating the same machine code and I'm quite certain
assigning a literal to any of the (U)Int32 or (U)Int16 types will generate
very similar if not identical code.
 
D

Daniel O'Connell [C# MVP]

This is fundamentally the same as
ldc.i4 0x0
ldc.i4 0x9b //note I may have the loads backwards here, I tend to
use conv.i8
//when I'm using MSIL
stloc.0

Err, that didn't come out right.
The actual instruction sequence is:
ldc.i4 0x0
ldc.i4 0x9b
stloc.0

the conv.i8 instruction was supposed to be part of the comments.
 
J

James Curran

Dennis Myrén said:
uint u = 123;
So, this means writing uint u = 123; means i first create an int
and then implicitly cast it to uint?

Yes & No.

The theory that's exactly what is happening -- Except that it's done by
the compiler at compile time, and the cast is a NOP (no operation).
Then, the above statement would result in twice the overhead
as just using an int, is that right?

Yes, but twice nothing is still nothing.
Or maybe the compiler is helping us to optimize this?
Yes, except it's not doing us a favor; it's required to do this (where
it can).

--
Truth,
James Curran
Home: www.noveltheory.com Work: www.njtheater.com
Blog: www.honestillusion.com Day Job: www.partsearch.com
(note new day job!)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top