Does pragmapack() in C programming have any usage apart from structure packing? - c

While I'm on an interview the interviewer asked me are there any other usage of pragmapack() in C apart from structure packing? So I answered that I don't know apart from structure packing. So are there any other usage of it?

#pragma pack(size)
is a preprocessor directive used for altering structure padding schemes. Usually a structure adds padding bytes between it's members to speed up the memory fetch operations.
the number of padding bytes it used is depends on machine architecture.
for example,
struct sample {
int a;
char b;
int c;
};
When we see the above structure it requires only 9 bytes ( 4 + 1 + 4) to hold members a, b and c, but for a 32 bit architecture, a variable of this structure takes 16 bytes (4 + 4 + 4) of memory. even though char b only requires 1 byte, it takes 4 bytes 1 for storing value of b and other three as padding bytes.
padding_size = (word_size of machine architecture > highest sized structure member datatype's size) ? highest sized structure member datatype's size : word_size of machine architecture;
we can forcefully assign padding size using preprocessor directive #pragma pack(size) , size should be a power of 2 less than the word_size of machine architecture.
If we use like
#pragma pack(1)
for the above structure then the total amount of memory required for holding a variable of type struct sample will be (4 + 1 + 4) 9 bytes.

Related

Question regarding disposition of C-struct members in memory

My question is based on the third case presented in this page:
https://www.geeksforgeeks.org/is-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member/
// C program to illustrate
// size of struct
#include <stdio.h>
int main()
{
struct C {
// sizeof(double) = 8
double z;
// sizeof(short int) = 2
short int y;
// Padding of 2 bytes
// sizeof(int) = 4
int x;
};
printf("Size of struct: %ld", sizeof(struct C));
return 0;
}
Why does it require a padding after y, instead of having a padding at the end (after x)?
I can see why it's needed on the cases 1st and 2nd, but I fail to see it on the 3rd.
In some computer architectures, instructions that access values in memory will only accept a subset of all addresses due to alignment restrictions. For example, an instruction that copies a 32-bit value from memory into a register might require the value to be at an address that's divisible by 4. (You might still be able to obtain the value byte-by-byte, but that would far slower as it would require multiple instructions). Other architectures might merely perform better if the value are aligned properly. And in yet other architectures, it might not matter at all.
As such, the C standard allows for implementation-specific padding to be used in structures. By adding padding, the compiler can assure that each member will be properly aligned (since it can enforce an alignment on the structure itself). This allows us to declare the following and let the compiler figure out the exact size and offsets:
struct A {
int x;
short y;
double z;
};
Let's look at what a compiler might do.
Let's say your system uses 2 bytes for short values, 4 bytes for int values and 8 bytes for double values. And let's say values of size N are required to be placed at an address evenly divisible by N.
struct A {
int x; // 4 bytes, address must be divisible by 4.
double z; // 8 bytes, address must be divisible by 8.
short y; // 2 bytes, address must be divisible by 2.
};
If we just put the members end to end, z would be found at offset 4, which isn't divisible by 8, so the computer would be unable to access this field efficiently. The compiler might therefore utilize padding.
struct A {
int x; // 4 bytes, address must be divisible by 4. // At offset 0.
// 4 bytes of padding. // At offset 4.
double z; // 8 bytes, address must be divisible by 8. // At offset 8.
short y; // 2 bytes, address must be divisible by 2. // At offset 16.
};
Now, z is at offset 8, which is divisible by 8.
But that's not quite it.
The alignment restrictions are imposed on the absolute address of the members, not merely their offset. So the members of struct C are only properly aligned if the address of the structure itself is at an address evenly divisible by 8. The compiler can take care of that when you do
struct A a;
But what if you do
struct A *array = malloc(sizeof(struct A) * n);
malloc will return a pointer that meets all possible alignment restrictions, so array[0] will be properly aligned, but what about array[1]? For that to be properly aligned, sizeof(struct A) needs to be a multiple of 8! So padding will be added to the end to make the size of the structure a multiple of 8, and we end up with this:
// Address must be divisible by 8, so sizeof(struct A) must be divisible by 8.
struct A {
int x; // 4 bytes, address must be divisible by 4. // At offset 0.
// 4 bytes of padding. // At offset 4.
double z; // 8 bytes, address must be divisible by 8. // At offset 8.
short y; // 2 bytes, address must be divisible by 2. // At offset 16.
// 2 bytes of padding. // At offset 18.
};
Finally, you asked about struct C. Applying the above, we get:
// Address must be divisible by 8, so sizeof(struct C) must be divisible by 8.
struct C {
double z; // 8 bytes, address must be divisible by 8. // At offset 0.
short y; // 2 bytes, address must be divisible by 2. // At offset 8.
// 2 bytes of padding. // At offset 10.
int x; // 4 bytes, address must be divisible by 4. // At offset 12.
// 0 bytes of padding. // At offset 16.
};
As described, by the site,
"C language doesn’t allow the compilers to reorder the struct members to reduce the amount of padding. In order to minimize the amount of padding, the struct members must be sorted in a descending order (similar to the case 2)."
This means that the padding for the structs are created right after they are made. C language can't reorder struct members, so the code runs like this: creates 8 bytes of storage for double z first, then creates 2 bytes of storage for short int y with a padding of 2 bytes, and finally creates 4 bytes of storage for int x. You should think of the padding as a package with the original storage: you can't separate them, which is why the padding of y is created before the storage for x is.
Edit: Sorry if my response was a little confusing or didn't answer the question. x is an int, so x doesn't have any padding. y is a short int, so it has the 2 byte padding. The padding doesn't at the end because it comes with the variable that requires it (y).
-mihirm

Finding addresses of structs with different instances

Studying for an exam and I came across an interesting question.
I have a struct:
struct vehicle {
long carId;
short wheels:3;
short fuelTank : 6;
short weight;
} x[5][5];
and the address of x is 0xaaa and memory is aligned at multiples of 4 what would be the address of x[1]?
I have no idea where to start but I found the size of the struct which is 16, and the size of struct when x[5][5] is 400 which is obviously a multiple of 16.
One of these is the answer:
a) 0xD2 b) 0xEA c)0xDC d) 0xAB
but i can not know how to get from 0xaaa to one of these.
As there is written in the question that "...memory is aligned at multiples of 4" it is supposed that type long occupies 4 bytes.
Two adjacent bit fields
short wheels:3;
short fuelTank : 6;
can be accomodate in one object of type short int . So they occupy two bytes (though in general case it is implementation defined) the same way as the next data member
short weight;
Thus we get the size of the structure is equal to 8 bytes.
x[1] is second element of the array and has type struct vechicle[5]
So as the size of the structure is equal to 8 then the size of the element of the array is equal to 8 * 5 = 40. In the hexadecimal notation it is equal to 0x28
Thus the address of the second element of the array that is of x[1] is
0xaaa
+
0x28
=====
0xad2

Sizeof a struct in C

Well, after reading this Size of structure with a char, a double, an int and a t I still don't get the size of my struct which is :
struct s {
char c1[3];
long long k;
char c2;
char *pt;
char c3;
}
And sizeof(struct s) returns me 40
But according to the post I mentioned, I thought that the memory should like this way:
0 1 2 3 4 5 6 7 8 9 a b c d e f
+-------------+- -+---------------------------+- - - - - - - -+
| c1 | |k | |
+-------------+- -+---------------------------+- - - - - - - -+
10 11 12 13 14 15 16 17
+---+- -+- -+- - - - - -+----+
|c2 | |pt | | c3 |
+---+- -+- -+- - - - - -+----+
And I should get 18 instead of 40...
Can someone explain to me what I am doing wrong ? Thank you very much !
Assuming an 8-byte pointer size and alignment requirement on long long and pointers, then:
3 bytes for c1
5 bytes padding
8 bytes for k
1 byte for c2
7 bytes padding
8 bytes for pt
1 byte for c3
7 bytes padding
That adds up to 40 bytes.
The trailing padding is allocated so that arrays of the structure keep all the elements of the structure properly aligned.
Note that the sizes, alignment requirements and therefore padding depend on the machine hardware, the compiler, and the platform's ABI (Application Binary Interface). The rules I used are common rules: an N-byte type (for N in {1, 2, 4, 8, 16 }) needs to be allocated on an N-byte boundary. Arrays (both within the structure and arrays of the structure) also need to be properly aligned. You can sometimes dink with the padding with #pragma directives; be cautious. It is usually better to lay out the structure with the most stringently aligned objects at the start and the less stringently aligned ones at the end.
If you used:
struct s2 {
long long k;
char *pt;
char c1[3];
char c2;
char c3;
};
the size required would be just 24 bytes, with just 3 bytes of trailing padding. Order does matter!
The size of the structure depends upon what compiler is used and what compiler options are enabled. The C language standard makes no promises about how memory is utilized when the compiler creates structures, and different architectures (for example 32-bit WinTel vs 64-bit WinTel) cause different layout decisions even when the same compiler is used.
Essentially, the size of a structure is equal to the sum of the size of the bytes needed by the field elements (which can generally be calculated) plus the sum of the padding bytes injected by the compiler (which is generally not known).
It is because of alignment, gcc has
#pragma pack(push,n)
// declare your struct here
#pragma pack(pop)
to change it. Read here, and also __attribute__((__packed__)).
If you declare the struct
struct packed
{
char c1[3];
long long k;
char c2;
char *pt;
char c3;
} __attribute__((__packed__));
then compiling with gcc, sizeof(packed) = 18 since
c1: 3
k : 8
c2: 1
pt: 4 // it depends
c3: 1
Apparently Visual C++ compiler supports #pragma pack(push,n) too.
what is a size of structure?
#include <stdio.h>
struct {
char a;
char b;
char c;
}st;
int main()
{
printf("%ld", sizeof(st));
return 0;
}
it shows 3 in gdb compiler.

Size of struct that contains two pointers

What is the size of this struct? (32 bit system calculation. Not 64 bit.)
struct list_element
{
short data;
struct list_element* next;
struct list_element* prev;
};
I have tried calculating the size with these formulas:
(sizeof(list_element*) + sizeof(short)) + ((sizeof(list_element*) * 2)
(4 + 2) + (4 * 2) = 6 + 8 = 14
(sizeof(short)) + (sizeof(list_element*) * 2)
2 + (4 * 2) = 2 + 8 = 10
(sizeof(list_element*) + sizeof(list_element*) + sizeof(short)) + (sizeof(list_element*) * 2)
(4 + 4 + 2) + (4 * 2) = 10 + 8 = 18
(sizeof(list_element*) + sizeof(list_element*) + sizeof(short))
(4 + 4 + 2) = 10
However, they do not return the correct answer. What formula do you use to calculate the size of this struct?
Update:
My teacher says we a re ignoring data alignment... Hopefully that does not throw anyone off too much since you are used handling data alignment with your code and structs...
Update 2
Thank you for the help and the introduction to data alignment.
The answer was 10 without data alignment... Not sure why I am in such a rush to work with data alignment in C... Is it fun?
Also, the answer with data alignment is 12. As you guys explained, you have to data align the short to match the integers. Therefore, you have (2 + (2 additional bytes)) + 4 + 4 = 12.
The size of the struct is given by:
size_t size = sizeof(struct list_element);
The fact that you have two members that are pointers to the struct just means
you are adding the size of a pointer, twice. On a 32 bit build, sizeof would resolve to an additional 4 bytes per pointer, on a 64 bit build, it would result in an additional 8 bytes per pointer.
Another thing to be aware of is that the size of your struct is likely not simply the sum of the sizeof's of the individual members, as storage in a struct is often padded for alignment purposes. So, between your short, and the next member, the padding will result in additional size.
The reason I used the word likely is that if a pragma pack directive was used in your source, the packing alignment could be changed, resulting in a different value for sizeof.
Two good discussions on struct alignment padding: A general discussion here, and How to reduce memory footprint here. The second link is particularly interesting as it deals with structure alignment, padding and bit fields, and how each can affect memory usage.
Although your teacher asked to ignore data alignment, the size of that struct is 10 bytes assuming short being 2 bytes.. but actually the short size is not fixed, but at least 2 bytes!
Give a look here. Did you correctly reported the teacher question?
This will return the size of the struct:
sizeof(struct list_element);

memory allocation for structures elements

Hi I am having difficulties in understanding about how the memory is allocated to the structure elements.
For example if i have the below structure and the size of char is 1 and int is 4 bytes respectively.
struct temp
{
char a;
int b;
};
I am aware that the size of the structure would be 8. Because there will be a padding of 3 bytes after the char, and the next element should be placed in multiple of 4 so the size will be 8.
Now consider the below structure.
struct temp
{
int a; // size is 4
double b; // size is 8
char c; // size is 4
double d; // size is 8
int e; // size is 4
};
This is the o/p i got for the above strucure
size of node is 40
the address of node is 3392515152 ( =: base)
the address of a in node is 3392515152 (base + 0)
the address of b in node is 3392515160 (base + 8)
the address of c in node is 3392515168 (base + 16)
the address of d in node is 3392515176 (base + 24)
the address of e in node is 3392515184 (base + 32)
The total memory sum up to 36 bytes, why does it show as 40 bytes?
If we create an array of such structure also the first element of the next array element can be place in 3392515188 (base + 36) as it is a multiple of 4, but why is it not happening this way?
Can any one plz solve my doubt.
Thanks in advance,
Saravana
It seems that on your system, double has to have the alignment of 8.
struct temp {
int a; // size is 4
// padding 4 bytes
double b; // size is 8
char c; // size is 1
// padding 7 bytes
double d; // size is 8
int e; // size is 4
// padding 4 bytes
};
// Total 4+4+8+1+7+8+4+4 = 40 bytes
Compiler adds an extra 4 bytes to the end of struct to make sure that array[1].b will be properly aligned.
Without end padding (assuming array is at address 0):
&array[0] == 0
&array[1] == 36
&array[1].b == 36 + 8 == 44
44 % 8 == 4 -> ERROR, not aligned!
With end padding (assuming array is at address 0):
&array[0] == 0
&array[1] == 40
&array[1].b == 40 + 8 == 48
48 % 8 == 0 -> OK!
Note that sizes, alignments, and paddings depend on target system and compiler in use.
In your calculation, you ignore the fact that e is subject to be padded as well:
The struct looks like
0 8 16 24 32
AAAAaaaaBBBBBBBBCcccccccDDDDDDDDEEEEeeee
where uppercase is the variable itself, and lowercase is the padding applied to it.
As you see (and as well from the addresses), each field is padded to 8 bytes, which is the largest field in the structure.
As the structure might be used in an array, and all array elements should be well-aligned as well, the padding to e is necessary.
It's heavily dependent on both your processor architecture and compiler. Modern machines and compilers may choose larger or smaller padding to reduce the access cost to data.
Four-byte alignment means that two address lines are unused. Eight, three. A chip can use that to address more memory (coarser grain) with the same amount of hardware.
A compiler might use a similar trick for various reasons, but no compiler is required to do anything but be no less fine-grained than the processor. Often, they'll just take the biggest-size value and use it exclusively for that block. In your case, that's a double, which is eight bytes.
This is a compiler dependent behavior.
Some compiler makes that 'double' to be stored after 8 bit offset.
IF you modify the structure as below you will get different result.
struct temp
{
double b; // size is 8
int a; // size is 4
int e; // size is 4
double d; // size is 8
char c; // size is 4
}
Every programmer should know what padding you compiler is doing.
E.g. If you are working on ARM platform and you set compiler settings to do not pad structure elements[ then accessing structure elements through pointers may generate 'odd' address for which processor generates an exception.
Every structure will also have alignment requirements
for example :
typedef struct structc_tag
{
char c;``
double d;
int s;
} structc_t;
Applying same analysis, structc_t needs sizeof(char) + 7 byte padding + sizeof(double) + sizeof(int) = 1 + 7 + 8 + 4 = 20 bytes. However, the sizeof(structc_t) will be 24 bytes. It is because, along with structure members, structure type variables will also have natural alignment. Let us understand it by an example. Say, we declared an array of structc_t as shown below structc_t structc_array[3];
Assume, the base address of structc_array is 0×0000 for easy calculations. If the structc_t occupies 20 (0×14) bytes as we calculated, the second structc_t array element (indexed at 1) will be at 0×0000 + 0×0014 = 0×0014. It is the start address of index 1 element of array. The double member of this structc_t will be allocated on 0×0014 + 0×1 + 0×7 = 0x001C (decimal 28) which is not multiple of 8 and conflicting with the alignment requirements of double. As we mentioned on the top, the alignment requirement of double is 8 bytes. In order to avoid such misalignment, compiler will introduce alignment requirement to every structure. It will be as that of the largest member of the structure. In our case alignment of structa_t is 2, structb_t is 4 and structc_t is 8. If we need nested structures, the size of largest inner structure will be the alignment of immediate larger structure.
In structc_t of the above program, there will be padding of 4 bytes after int member to make the structure size multiple of its alignment. Thus the sizeof (structc_t) is 24 bytes. It guarantees correct alignment even in arrays. You can cross check
to avoid structure padding!
#pragma pack ( 1 ) directive can be used for arranging memory for structure members very next to the end of other structure members.
#pragma pack(1)
struct temp
{
int a; // size is 4
int b; // size is 4
double s; // size is 8
char ch; //size is 1
};
size of structure would be:17
If we create an array of such structure also the first element of the next array element can be place in 3392515188 (base + 36) as it is a multiple of 4, but why is it not happening this way?
It can't because of the double elements in there.
It's clear that the compiler and architecture you are using requires a double to be eight byte aligned. This is obvious because there is seven bytes of padding after the char c.
This requirement also means that the entire struct must be eight byte aligned. There's no point in carefully making all the doubles aligned to eight bytes relative to the start of the struct if the struct itself is only four byte aligned. Hence the padding after the final int to make sizeof(temp) a multiple of eight.
Note that this alignment requirement need not be a hard requirement. The compiler could choose to do the alignment even if doubles can be four byte aligned on the grounds that it might take more memory cycles to access the double if it's only four byte aligned.

Resources