#include <stdio.h>
typedef struct { char* c; char b; } a;
int main()
{
printf("sizeof(a) == %d", sizeof(a));
}
I get "sizeof(a) == 8", on a 32-bit machine. The total size of the structure will depend on the packing: In my case, the default packing is 4, so 'c' takes 4 bytes, 'b' takes one byte, leaving 3 padding bytes to bring it to the next multiple of 4: 8. If you want to alter this packing, most compilers have a way to alter it, for example, on MSVC:
#pragma pack(1)
typedef struct { char* c; char b; } a;
gives sizeof(a) == 5. If you do this, be careful to reset the packing before any library headers!
Answer from Simon Buchan on Stack Overflow#include <stdio.h>
typedef struct { char* c; char b; } a;
int main()
{
printf("sizeof(a) == %d", sizeof(a));
}
I get "sizeof(a) == 8", on a 32-bit machine. The total size of the structure will depend on the packing: In my case, the default packing is 4, so 'c' takes 4 bytes, 'b' takes one byte, leaving 3 padding bytes to bring it to the next multiple of 4: 8. If you want to alter this packing, most compilers have a way to alter it, for example, on MSVC:
#pragma pack(1)
typedef struct { char* c; char b; } a;
gives sizeof(a) == 5. If you do this, be careful to reset the packing before any library headers!
Contrary to what some of the other answers have said, on most systems, in the absence of a pragma or compiler option, the size of the structure will be at least 6 bytes and, on most 32-bit systems, 8 bytes. For 64-bit systems, the size could easily be 16 bytes. Alignment does come into play; always. The sizeof a single struct has to be such that an array of those sizes can be allocated and the individual members of the array are sufficiently aligned for the processor in question. Consequently, if the size of the struct was 5 as others have hypothesized, then an array of two such structures would be 10 bytes long, and the char pointer in the second array member would be aligned on an odd byte, which would (on most processors) cause a major bottleneck in the performance.
size of struct in C - Stack Overflow
Total bytes for fields in Structure - C++ Forum
Struct with specific byte size and layout
Struct; What is 16 Bytes?
So, there's a broad rule of thumb about structs: They are best used for encapsulating data that is not more than 16 bytes, otherwise there is a diminishing performance benefit.
Yea makes sense, I guess.
I was able to look up that a float takes 4 bytes, a double takes 8 bytes. Does a Boolean value in a Struct really only take up 1 bit?
Worded differently: Is a Struct with 128 boolean fields a 16 byte struct?
The compiler may add padding for alignment requirements. Note that this applies not only to padding between the fields of a struct, but also may apply to the end of the struct (so that arrays of the structure type will have each element properly aligned).
For example:
struct foo_t {
int x;
char c;
};
Even though the c field doesn't need padding, the struct will generally have a sizeof(struct foo_t) == 8 (on a 32-bit system - rather a system with a 32-bit int type) because there will need to be 3 bytes of padding after the c field.
Note that the padding might not be required by the system (like x86 or Cortex M3) but compilers might still add it for performance reasons.
Aligning to 6 bytes is not weird, because it is aligning to addresses multiple to 4.
So basically you have 34 bytes in your structure and the next structure should be placed on the address, that is multiple to 4. The closest value after 34 is 36. And this padding area counts into the size of the structure.
From what I've read, a struct should only be used if it's 16 bytes or less; otherwise it should be a class.
I don't have a benchmark to what 16 bytes looks like, so I have no idea when to use a struct. Does anyone have an example of code that's close to 16 bytes so I can get a better understanding of when to use it/not use it?
I'm wondering whether
sizeof(struct fakes)andsizeof(*fakes)are the same.
Yes, they are guaranteed to be the same.
Yes. These are the same.
sizeof is used to determine the amount of space a datatype occupies in memory. The compiler is really only concerned with the type, and not a particular instance of it (because all instances should take up the same amount of space). So sizeof(struct fakes) is guaranteed to be the same assizeof(*fakes).
You should prefer small structs because structs will likely be copied, and smaller structs are cheaper to copy.
The docs do provide a bit more context for that 16-byte size limit:
Next, reference type assignments copy the reference, whereas value type assignments copy the entire value. Therefore, assignments of large reference types are cheaper than assignments of large value types.
Assuming a word size of 8 bytes, a 16-byte struct is only twice as large as a pointer to a reference type, thus still comparably efficient to copy.
This is completely unrelated to limited stack size. The stack typically has far more space than you might think, unless you're writing deeply recursive algorithms.
In C and C++, it is common to store significant amounts of data on the stack, and these languages only have value types. But unlike C# they can specify whether a struct is passed by value (and thus copied), or by reference or pointer (without a copy). The C++ Core Guidelines recommend that parameters are passed by reference, unless the type is known to be be efficiently copyable (trivially copyable without invoking copy constructors, and only up to two or three words large). Under those circumstances, a copy is more efficient than passing by reference because the copy avoids pointer indirection.
I know that one reason for keeping it under 16 bytes is that structs are intended to be used on the stack.
The manner in which structs are stored in C# is an implementation detail. They might be stored on the stack, but they might not.
Does this 16 byte rule still make sense in a situation where I use a struct as a private field in a class?
What matters is whether you want value or reference semantics, not the absolute size of the struct. If you're willing to put up with the copying, your structs can be as large as you want. In most cases, however, you're going to be better served by using classes for larger data types.
Further Reading
The Truth About Value Types
The C standard allows implementations to add additional padding bits to structures so as to access the structure faster by making it aligned to byte boundaries as required by that implementation.
This is known as Structure Padding.
Given the above the size of a structure may not be the same as the sum of the sizes of the individual members. You should always use sizeof to determine the size of structure.
Also, the above mentioned is the reason that you do not see the structures members placed at memory addresses you expect them to be at.
You are running into alignment rules. This is a very compiler- and system-specific thing, but by default (that is, unless you specify otherwise using compiler flags or special alignment requests in the code) GCC on x64 Linux aligns each field of a struct on a multiple of its size. So, a one-character byte has nothing in particular to worry about for alignment. However, an int or float is always placed on a 4-byte boundary, and a double is always placed on an 8-byte boundary. That's what you are seeing here.
As Ethan notes above in the comments, some processors won't even access memory objects that aren't aligned a certain way, and Intel processors will access memory much more slowly if it isn't aligned.
You're misquoting the book (at least the 2nd edition). Jeffrey Richter states value types can be more than 16 bytes if:
You don't intend to pass them to other methods or copy them to and from a collection class.
Additionally Eric Gunnerson adds (regarding the 16 byte limit)
Use this guideline as a trigger to do more investigation.
It is simply not true that a struct "has to be less than 16 bytes in size". It all depends on usage.
If you are creating the struct and also consuming it and are worried about performance then use a profiler comparing a struct vs class to see which works best for you.
Only you know how your structs are being used in your program. But if nothing else, you can always test it for yourself. For instance, if it's frequently passed to other functions, the following may illuminate you:
class MainClass
{
static void Main()
{
Struct64 s1 = new Struct64();
Class64 c1 = new Class64();
DoStuff(s1);
DoStuff(c1);
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 10000; i++)
{
s1 = DoStuff(s1);
}
sw.Stop();
Console.WriteLine("Struct {0}", sw.ElapsedTicks);
sw.Reset();
sw.Start();
for (int i = 0; i < 10000; i++)
{
c1 = DoStuff(c1);
}
sw.Stop();
Console.WriteLine("Class {0}", sw.ElapsedTicks);
sw.Reset();
Console.ReadLine();
}
}
with:
public class Class64
{
public long l1;
public long l2;
public long l3;
public long l4;
public long l5;
public long l6;
public long l7;
public long l8;
}
public struct Struct64
{
public long l1;
public long l2;
public long l3;
public long l4;
public long l5;
public long l6;
public long l7;
public long l8;
}
Try this sort of thing with representative structs/classes, and see what results you get. (On my machine, above test, the class seems ~3 times faster)