Why doesn't size of struct is equals to sum of sizes of its individual member types? [duplicate] - c

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Why isn’t sizeof for a struct equal to the sum of sizeof of each member?
I guess similar (duplicate) questions must have been asked on SO before. But I'm unable to find them. Basically I don't know what to search for. So asking it here.
Why doesn't size of struct is equals to sum of sizes of its individual member types?
I'm using visual C++ compiler.
For example, assuming 32-bit machine. {=> sizeof(int) == 4; sizeof(char) == 1; sizeof(short) == 2; }
struct {
int k;
char c;
} s;
The size expected is 4+1 = 5; but sizeof(s) gives 8. Here char is occupying 4 bytes instead of 1. I don't know the exact reason for this but my guess is compiler is doing so for efficiency purposes.
struct{
long long k;
int i;
} s;
expected size is 4+4 = 8 (on 32 bit machine) and 8+4=12 (on 64 bit machine). But strangely sizeof(s) give 16. Here both int & long long are occupying 8 bytes each.
What is this thing called?
What exactly is going on?
Why is compiler doing this?
Is there a way to tell compiler to stop doing this?

It is because the compiler uses padding to bring each element into word alignment that is specific to the architecture for which you are compiling.
It can be for one of several reasons but usually:
Because some CPU's simply cannot read a long or long long multi-byte value when it isn't on an address multiple of its own size.
Because CPU's that can read off-aligned data may do it much slower than aligned.
You can often force it off with a compiler-specific directive or pragma.
When you do this, the compiler will generate relatively inefficient code to access the off-aligned data using multiple read/write operations.

This is called padding; which involves adding some more bytes in order to align the structure on addresses that are divisible by some special number, usually 2, 4, or 8. A compiler can even place padding between members to align the fields themselves on those boundaries.
This is a performance optimization: access to aligned memory addresses is faster, and some architectures don't even support accessing unaligned addresses.
For VC++, you can use the pack pragma to control padding between fields. However, note that different compilers have different ways of handling this, so if, for example, you also want to support GCC, you'll have to use a different declaration for that.

The compiler can insert padding between members or at the end of the struct. Padding between members is typically done to keep the members aligned to maximize access speed. Padding at the end is done for roughly the same reason, in case you decide to create an array of the structs.
To prevent it from happening, you use something like #pragma pack(1).

Related

Alignment in 64bit machine is not 8 Bytes

I am trying to find out alignment on my 64bit machine(Win10 on Intel iCore7). I thought of this experiment:
void check_alignment(char c1, char c2 )
{
printf("delta=%d\n", (int)&c2 - (int)&c1); // prints 4 instead of 8
}
void main(){
check_alignment('a','b');
}
I was expecting delta=8. Since it's 64bit machine char c1 and char c2 should be stored on multiples of 8. Isn't that right?
Even if we assume compiler has done optimization to have them stored in less space, why not just store them back to back delta=1? Why 4 byte alignment?
I repeated the above experiment with float types, and still gives delta=4
void check_alignment(float f1, float f2 )
{
printf("delta=%d\n", (int)&c2 - (int)&c1); // prints 4
}
void main(){
check_alignment(1.0,1.1);
}
Firstly, if your platform is 64-bit, then why are you casting your pointer values to int? Is int 64-bit wide on your platform? If not, your subtraction is likely to produce a meaningless result. Use intptr_t or ptrdiff_t for that purpose, not int.
Secondly, in a typical implementation a 1-byte type will typically be aligned at 1-byte boundary, regardless of whether your platform is 64-bit or not. To see a 8-byte alignment you'd need a 8-byte type. And in order to see how it is aligned you have to inspect the physical value of the address (i.e. whether it is divisible by 1, 2, 4, 8 etc.), not analyze how far apart two variables are spaced.
Thirdly, how far apart c1 and c2 are in memory has little to do with alignment requirements of char type. It is determined by how char values are passed (or stored locally) on your platform. In your case they are apparently allocated 4-byte storage cells each. That's perfectly fine. Nobody every promised you that two unrelated objects with 1-byte alignment will be packed next to each other as tightly as possible.
If you want to determine alignment by measuring how far from each other two objects are stored, declare an array. Do not try to measure the distance between two independent objects - this is meaningless.
To determine the greatest fundamental alignment in your C implementation, use:
#include <stdio.h>
#include <stddef.h>
int main(void)
{
printf("%zd bytes\n", _Alignof(max_align_t));
}
To determine the alignment requirement of any particular type, replace max_align_t above with that type.
Alignment is not purely a function of the processor or other hardware. Hardware might support aligned or unaligned accesses with different performance effects, and some instructions might support unaligned access while others do not. A particular C implementation might choose to require or not require certain alignment in combination with choosing to use or not use various instructions. Additionally, on some hardware, whether unaligned access is supported is configurable by the operating system.

Why does an int take up 4 bytes in c or any other language? [duplicate]

This question already has answers here:
size of int variable
(6 answers)
Closed 5 years ago.
This is a bit of a general question and not completely related to the c programming language but it's what I'm on studying at the moment.
Why does an integer take up 4 bytes or How ever many bytes dependant on the system?
Why does it not take up 1 byte per integer?
For example why does the following take up 8 bytes:
int a = 1;
int b = 1;
Thanks
I am not sure whether you are asking why int objects have fixed sizes instead of variable sizes or whether you are asking why int objects have the fixed sizes they do. This answers the former.
We do not want the basic types to have variable lengths. That makes it very complicated to work with them.
We want them to have fixed lengths, because then it is much easier to generate instructions to operate on them. Also, the operations will be faster.
If the size of an int were variable, consider what happens when you do:
b = 3;
b += 100000;
scanf("%d", &b);
When b is first assigned, only one byte is needed. Then, when the addition is performed, the compiler needs more space. But b might have neighbors in memory, so the compiler cannot just grow it in place. It has to release the old memory and allocate new memory somewhere.
Then, when we do the scanf, the compiler does not know how much data is coming. scanf will have to do some very complicated work to grow b over and over again as it reads more digits. And, when it is done, how does it let you know where the new b is? The compiler has to have some mechanism to update the location for b. This is hard and complicated and will cause additional problems.
In contrast, if b has a fixed size of four bytes, this is easy. For the assignment, write 3 to b. For the addition, add 100000 to the value in b and write the result to b. For the scanf, pass the address of b to scanf and let it write the new value to b. This is easy.
The basic integral type int is guaranteed to have at least 16 bits; At least means that compilers/architectures may also provide more bits, and on 32/64 bit systems int will most likely comprise 32 bits or 64 bits (i.e. 4 bytes or 8 bytes), respectively (cf, for example, cppreference.com):
Integer types
... int (also accessible as signed int): This is the most optimal
integer type for the platform, and is guaranteed to be at least 16
bits. Most current systems use 32 bits (see Data models below).
If you want an integral type with exactly 8 bits, use the int8_t or uint8_t.
It doesn't. It's implementation-defined. A signed int in gcc on an Atmel 8-bit microcontroller, for example, is a 16-bit integer. An unsigned int is also 16-bits, but from 0-65535 since it's unsigned.
The fact that an int uses a fixed number of bytes (such as 4) is a compiler/CPU efficiency and limitation, designed to make common integer operations fast and efficient.
There are types (such as BigInteger in Java) that take a variable amount of space. These types would have 2 fields, the first being the number of words being used to represent the integer, and the second being the array of words. You could define your own VarInt type, something like:
struct VarInt {
char length;
char bytes[]; // Variable length
}
VarInt one = {1, {1}}; // 2 bytes
VarInt v257 = {2, {1,1}}; // 3 bytes
VarInt v65537 = {4, {1,0,0,1}}; // 5 bytes
and so on, but this would not be very fast to perform arithmetic on. You'd have to decide how you would want to treat overflow; resizing the storage would require dynamic memory allocation.

Can I cast pointers like this?

Code:
unsigned char array_add[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
...
if ((*((uint32_t*)array_add)!=0)||(*((uint32_t*)array_add+1)!=0))
{
...
}
I want to check if the array is all zero. So naturally I thought of casting the address of an array, which also happens to be the address of the first member, to an unsigned int 32 type, so I'll only need to do this twice, since it's a 64 bit, 8 byte array. Problem is, it was successfully compiled but the program crashes every time around here.
I'm running my program on an 8bit microcontroller, cortex-M0.
How wrong am I?
In theory this could work but in practice there is a thing you aren't considering: aligned memory accesses.
If a uint32_t requires aligned memory access (eg to 4 bytes), then casting an array of unsigned char which has 1 byte alignment requirement to an uint32_t* produces a pointer to an unaligned array of uint32_t.
According to documentation:
There is no support for unaligned accesses on the Cortex-M0 processor. Any attempt to perform an unaligned memory access operation results in a HardFault exception.
In practice this is just dangerous and fragile code which invokes undefined behavior in certain circumstances, as pointed out by Olaf and better explained here.
To test multiple bytes as once code could use memcmp().
How speedy this is depends more on the compiler as a optimizing compiler may simple emit code that does a quick 8 byte at once (or 2 4-byte) compare. Even the memcmp() might not be too slow on an 8-bit processor. Profiling code helps.
Take care in micro-optimizations, as they too often are not efficient use of coders` time for significant optimizations.
unsigned char array_add[8] = ...
const unsigned char array_zero[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
if (memcmp(array_zero, array_add, 8) == 0) ...
Another method uses a union. Be careful not to assume if add.arr8[0] is the most or least significant byte.
union {
uint8_t array8[8];
uint64_t array64;
} add;
// below code will check all 8 of the add.array8[] is they are zero.
if (add.array64 == 0)
In general, focus on writing clear code and reserve such small optimizations to very select cases.
I am not sure but if your array has 8 bytes then just assign base address to a long long variable and compare it to 0. That should solve your problem of checking if the array is all 0.
Edit 1: After Olaf's comment I would say that replace long long with int64_t. However, why do you not a simple loop for iterating the array and checking. 8 chars is all you need to compare.
Edit 2: The other approach could be to OR all elements of array and then compare with 0. If all are 0 then OR will be zero. I do not know whether CMP will be fast or OR. Please refer to Cortex-M0 docs for exact CPU cycles requirement, however, I would expect CMP to be slower.

Understanding memory alignment constraints and padding bytes in C

I have following code snippet.
#include<stdio.h>
int main(){
typedef struct{
int a;
int b;
int c;
char ch1;
int d;
} str;
printf("Size: %d \n",sizeof(str));
return 0;
}
Which is giving output as follows
Size: 20
I know that size of the structure is greater than the summation of the sizes of components of the structure because of padding added to satisfy memeory alignment constraints.
I want to know how it is decided that how many bytes of padding have to be added. On what does it depend ? Does it depends on CPU architecture ? And does it depends on compiler also ? I am using here 64bit CPU and gcc compiler. How will the output change if these parameters change.
I know there are similar questions on StackOverflow, but they do not explain this memory alignment constraints thoroughly.
It in general depends on the requirements of the architecture. There's loads over here, but it can be summarized as follows:
Storage for the basic C datatypes on an x86 or ARM processor doesn’t
normally start at arbitrary byte addresses in memory. Rather, each
type except char has an alignment requirement; chars can start on any
byte address, but 2-byte shorts must start on an even address, 4-byte
ints or floats must start on an address divisible by 4, and 8-byte
longs or doubles must start on an address divisible by 8. Signed or
unsigned makes no difference.
In your case the following is probably taking place: sizeof(str) = 4 (4 bytes for int) + 4 (4 bytes for int) + 1 ( 1 byte for char) + 7 (3 bytes padding + 4 bytes for int) = 20
The padding is there so that int is at an address that's a multiple of 4 bytes. This requirement comes from the fact that int is 4 bytes long (my assumption regarding the architecture you're using). But this will vary from one architecture to another.
On what does it depend ? Does it depends on CPU architecture ? And does it depends on compiler also ?
CPU, operating system, and compiler at least.
I know that it depends on the CPU architecture, I think you can find some interesting articles that talks about this on the net, wikipedia is not bad in my opinion.
For me I am using a 64 bit linux machine, and what I can say is that, every field is aligned so that it would be on a memory address divisible by its size (for basic types), for example :
int and float are aligned by 4 (must be in a memory adress divisible by 4)
char and bool by 1 ( which means no padding)
double and pointers are aligned by 8
Best way to avoid padding is to put your fields from largest size to smallest (when there is only basic fields)
When there is composed fields, it a little more difficult for me to explain here, but I think you can figure it out yourself in a paper

Bit field manipulation disadvantages

I was reading this link
http://dec.bournemouth.ac.uk/staff/awatson/micro/articles/9907feat2.htm
I could not understand this following statements from the link, Please help me understand about this.
The programmer just writes some macros that shift or mask the
appropriate bits to get what is desired. However, if the data involves
longer binary encoded records, the C API runs into a problem. I have,
over the years, seen many lengthy, complex binary records described
with the short or long integer bit-field definition facilities. C
limits these bit fields to subfields of integer-defined variables,
which implies two limitations: first of all, that bit fields may be no
wider, in bits, than the underlying variable; and secondly, that no
bit field should overlap the underlying variable boundaries. Complex
records are usually composed of several contiguous long integers
populated with bit-subfield definitions.
ANSI-compliant compilers are free to impose these size and alignment
restrictions and to specify, in an implementation-dependent but
predictable way, how bit fields are packed into the underlying machine
word structure. Structure memory alignment often isn’t portable, but
bit field memory is even less so.
What i have understood from these statements is that the macros can be used to mask the bits to left or right shift. But i had this doubt in my mind why do they use macros? - I thought by defining it in macros the portability can be established irrespective of 16-bit or 32-bit OS..Is it true?I could not understand the two disadvantages mentioned in the above statement.1.bit fields may be no wider 2.no bit field should overlap the underlying variable boundaries
and the line,
Complex records are usually composed of several contiguous long integers
populated with bit-subfield definitions.
1.bit fields may be no wider
Let's say you want a bitfield that is 200 bits long.
struct my_struct {
int my_field:200; /* Illegal! No integer type has 200 bits --> compile error!
} v;
2.no bit field should overlap the underlying variable boundaries
Let's say you want two 30 bit bitfields and that the compiler uses a 32 bit integer as the underlying variable.
struct my_struct {
unsigned int my_field1:30;
unsigned int my_field2:30; /* Without padding this field will overlap a 32-bit boundary */
} v;
Ususally, the compiler will add padding automatically, generating a struct with the following layout:
struct my_struct {
unsigned int my_field1:30;
:2 /* padding added by the compiler */
unsigned int my_field2:30; /* Without padding this field will overlap a 32-bit boundary */
:2 /* padding added by the compiler */
} v;

Resources