Structs in C#

G

Guest

Hi

Can anyone tell me how C# allocates memory for structs in C#? I am having
problems figuring out how much memory will be allocated. Consider the
following snippet

struct S1
{
int i;
char c;
}

I expect the size of this struct to be 6 bytes but it turns out to be 8
bytes. If I add a double then the size is 16 bytes.

struct S1
{
int i;
char c;
double d;
}

If after the double I include a byte then the size is 24 bytes !!!!!

struct S1
{
int a;
char c;
double d;
byte b;
}

Can anyone tell me why this strange behaviour? What is the rationale behind
such memory allocation?
 
F

Francois PIETTE

What is the rationale behind such memory allocation?

Data alignment which result in better performance.
This is common to many languages even outside of .NET world.
 
J

Jon Skeet [C# MVP]

Venkataramana said:
Can anyone tell me how C# allocates memory for structs in C#? I am having
problems figuring out how much memory will be allocated. Consider the
following snippet

struct S1
{
int i;
char c;
}

I expect the size of this struct to be 6 bytes but it turns out to be 8
bytes.

Could you tell us how you're measuring this size?

Jon
 
C

Carl Daniel [VC++ MVP]

Venkataramana said:
Hi

Can anyone tell me how C# allocates memory for structs in C#?

It's up to the CLR, not the language. Object layout is simply not a
language concept in .NET.

I am
having problems figuring out how much memory will be allocated.
Consider the following snippet

struct S1
{
int i;
char c;
}

I expect the size of this struct to be 6 bytes but it turns out to be
8 bytes.

This is exactly what I'd expect from C or C++: the struct is a multiple of
the most restritive alignment, in this case, the int has an alignment of 4,
so the size is a multiple of 4.
If I add a double then the size is 16 bytes.

struct S1
{
int i;
char c;
double d;
}

Again, the size is a multiple of the most restrictive alignment. double has
an alignment of 8, so the size is a multiple of 8.
If after the double I include a byte then the size is 24 bytes !!!!!

struct S1
{
int a;
char c;
double d;
byte b;
}

And again, it must be a multiple of 8, but you've added data beyond byte 16,
so the size bumps up to 24 to maintain alignment.
Can anyone tell me why this strange behaviour? What is the rationale
behind such memory allocation?

Alignment, Alignment, Alignment. It's exactly the sizes that these structs
would have in C/C++ with VC++ (or most any 32-bit C or C++ compiler).

If you need to control struct layout, you can do so explicitly using the
StructLayout and FieldOffset attributes in the
System.Runtime.InteropServices namespace.

-cd
 
W

Willy Denoyette [MVP]

| Hi
|
| Can anyone tell me how C# allocates memory for structs in C#? I am having
| problems figuring out how much memory will be allocated. Consider the
| following snippet
|
| struct S1
| {
| int i;
| char c;
| }
|
| I expect the size of this struct to be 6 bytes but it turns out to be 8
| bytes. If I add a double then the size is 16 bytes.
|
| struct S1
| {
| int i;
| char c;
| double d;
| }
|
| If after the double I include a byte then the size is 24 bytes !!!!!
|
| struct S1
| {
| int a;
| char c;
| double d;
| byte b;
| }
|
| Can anyone tell me why this strange behaviour? What is the rationale
behind
| such memory allocation?
|
| --
| A.N.S.Venkataramana
| Software Engineer
| NCR Corporation
| Hyderabad

Guess you are using Marshal.SizeOf(..) to determine the size of a struct,
however, this function returns the 'marshaled' size, which is not
necessarily the same as the size in memory as it is subject to alignment and
padding. Note that the CLR controls the layout of any managed object in
memory, you can only control the layout as it would appear at the unmanaged
side when marshaling the object (struct or class). Check
StructLayoutAttribute in the docs, the LayoutKind.Explicit enum allows you
to control the layout (and thus the size of the marshaled struct) from your
code instead of using the default (LayoutKind.Sequential).

Willy.
 
C

Claes Bergefall

The memory is aligned on 8-byte boundaries. There are a bunch of reasons for
this (mainly for performance), just do a search on Google and you should
find it. You can change it using the StructLayoutAttribute.

/claes
 
L

Larry Smith

It has to do with alignment.

Remember that the CLR is designed to run on multiple CPU architectures.
On 32 bit machines, the hardware is usually optimized to fetch data from
memory addresses that are a multiple of 4. So suppose you (somehow) had
a reference to a struct at address 0 (in really, really low memory)
[Side note: null pointers in C/C++ are so common that Windows makes low
memory unavailable for even reading, to help debugging].

If your struct had { char c; int x; }, then naively you'd expect x to be
at memory address 2. But that would mean that the hardware would have to
fetch the 4 bytes from address 0 and remember the two bytes it needs
from there, then fetch the 4 bytes from address 4, and again grab two
bytes, and finally glue the two chunks together to give you the value of
x. Can't you just see your program slowing down tremendously if you did
this in an inner loop?

Indeed, on some CPU architectures, they don't support this at all. If
you tried to fetch a 32-bit value from an address that wasn't a multiple
of 4, the native machine language instruction would fault (roughly the
same way a DIVide opcode would fault if you tried to divide by zero).

And in some cases, doubles (8 byte fields) should/must be on 8-byte
address boundaries.

So in our above case, one way around this would be to insert two
internal pad bytes (uninitialized, unused) between c and x. If you've
ever done any C/C++ programming, you might be familiar with #pragma
pack, which does the same type of thing.

But now we have to take arrays into consideration. Take your struct S1,
with an int and a char. Yes it could fit into 6 bytes. But if you had an
array of them, while S1[0].x would be at address 0, S1[1].x would be at
address 6. Uh-oh. So let's pad each struct out to a multiple of 8, and
then things are guaranteed (well, depending on your CPU architecture;
it's not inconceivable that some day, on "Win-128", we might pad it out
to 16 byte multiples) to be aligned.

Uh, one more thing. The CLR doesn't necessarily do padding that way. It
assumes it can reorder your data fields (!!!). I recently wrote a reply
to someone else. See, in this newsgroup, my article "Re: Convert from
byte[] to structure value", posted 8/10/2006, 3:27PM.

And you thought struct's were simple! :)
 
M

Michael D. Ober

Carl Daniel said:
It's up to the CLR, not the language. Object layout is simply not a
language concept in .NET.

Which is why there is a class that allows you to create bitmaps. Sometimes,
object layout is important, especially if you are communicating with
external devices.

Mike.
 
M

Michael D. Ober

Every processor has a "native" address scheme that is faster than others.
On 32-bit Intel chips, this scheme is by using addresses that are multiples
of 4. Thus, a one byte ASCII Char or two byte Unicode Char will both take 4
bytes. On a 64-bit system, the multiplier is 8. For performance reasons,
you will want to honor this processor specific concept. The only time you
wouldn't want to do this is when you are interfacing to a device that uses a
different native address scheme, in which case you would need to force your
program to that device's scheme. The MS and GNU C++ compilers can do this.
MS C uses the "#pragma pack <n>" to control the boundary information. Does
C# have a similar construct?

Mike Ober.
 
M

Michael D. Ober

Doesn't matter - for performance reasons, char c will allocate 4 bytes on a
x86-32 processor. On a x86-16 (8086) it will allocate 2 bytes and on a
x86-64 it will allocate 8 bytes.

Mike Ober.
 
J

Jon Skeet [C# MVP]

Michael D. Ober said:
Doesn't matter - for performance reasons, char c will allocate 4 bytes on a
x86-32 processor. On a x86-16 (8086) it will allocate 2 bytes and on a
x86-64 it will allocate 8 bytes.

But the measurement method still matters - there's a difference between
using sizeof() and using Marshal.SizeOf, for instance.
 
B

Barry Kelly

Michael D. Ober said:
The MS and GNU C++ compilers can do this.
MS C uses the "#pragma pack <n>" to control the boundary information. Does
C# have a similar construct?

Yes - with no modifiers, the JIT is free to produce code specifically
tailored for the CPU on the system. When interacting with unmanaged code
is required, one can use FieldOffset and StructLayout attributes to
specify things exactly.

-- Barry
 
G

Guest

Hi

I am using unsafe block and sizeof keyword to get the size.
--
A.N.S.Venkataramana
Software Engineer
Apex CoVantage India
Hyderabad
 

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