I have struct in C:
typedef struct Node {
int data; // 4 bytes int + 4 bytes for alignment
struct Node* prev; // 8 bytes pointer
struct Node* next; // 8 bytes pointer
} Node;
The size of this struct is 24 bytes (8 + 8 + 8). When I use the sizeof(Node), the compiler also shows 24 bytes.
However, when I create two or more structs on the heap (one after another) and look at their memory location, there are 8 byte gaps between each Node struct.
For example:
11121344 (the 1st Node address)
11121376 (the 2nd Node address) // 376-344 = 32-24 = 8 extra bytes
11121408 (the 3rd Node address) // 408-376 = 32-24 = 8 extra bytes
Can you explain why compiler separates Node structs by adding 8 bytes between Nodes?
There are 2 possible reasons for your observation:
The C standard requires that malloc always returns memory chunks with maximum alignment to prevent alignment issues no matter what you allocate for.
malloc manages memory chunks internally by using some sort of data structures. Depending on the implementation, it would add additional information to each memory chunk for internal usage. For instance, malloc could manage memory chunks in a linked list, then it would require each chunk to hold an additional pointer that points to the next chunk.
The maximum alignment depends on the architecture and the compiler / malloc - implementation used.
For your case and assuming glibc, taken straight out of the docs of glibc/malloc.c :
Alignment: 2 * sizeof(size_t) (default)
(i.e., 8 byte alignment with 4byte size_t). This suffices for
nearly all current machines and C compilers. However, you can
define MALLOC_ALIGNMENT to be wider than this if necessary.
Minimum overhead per allocated chunk: 4 or 8 bytes
Each malloced chunk has a hidden word of overhead holding size
and status information.
Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead)
8-byte ptrs: 24/32 bytes (including, 4/8 overhead)
Thus malloc in your case will align to 2 * sizeof(size_t) = 16 bytes.
Also note the 'hidden overhead' mentioned. This overhead is due store additional internal information used for memory management...
Can you explain why compiler separates Node structs by adding 8 bytes between Nodes?
It's a coincidence. There is no rule about how to lay out memory for any sequence of malloc() calls.
The address can be ascending with a fixed interval, descending with varying intervals, (seemingly) random, ..., ....
If you want fixed relative addresses use an array
struct Node arr[3];
ptrdiff_t delta10 = &arr[1] - &arr[0];
ptrdiff_t delta20 = &arr[2] - &arr[0];
ptrdiff_t delta21 = &arr[2] - &arr[1];
if (delta10 != delta21) /* cannot happen */;
or allocate a group of elements (maybe with realloc()) at the same time
struct Node *elements = malloc(3 * sizeof *elements);
ptrdiff_t delta10 = &elements[1] - &elements[0];
ptrdiff_t delta20 = &elements[2] - &elements[0];
ptrdiff_t delta21 = &elements[2] - &elements[1];
if (delta10 != delta21) /* cannot happen */;
free(elements);
Related
I'm curious, how exactly does memory allocation looks like after calling struct list x; for code bellow:
struct list {
int key;
char name[10];
struct list* ptr;
};
Variable x will store 4 bytes for key, 10 bytes for name and how much bytes for ptr?
struct list will be allocated as a single contiguous block of memory likely containing the following (assuming sizeof(int) == 4 for this platform and toolchain. I use the word "likely" because some considerations here are actually implementation-defined.
Four bytes for key.
Ten bytes for name.
Padding bytes to align ptr to the expected alignment.
sizeof(list*) bytes for a pointer. On a modern-day desktop computer using a common operating system and ABI (meaning a flat addressing model), I could guess that it's likely to be 4 or 8 bytes for 32-bit and 64-bit systems respectively. In reality, a pointer's size is implementation-defined and depends on a number of factors, as Eric Postpischil adds:
...the C standard permits pointers to be different sizes depending on the types they point to. For example, in old word-addressed computers, some pointers may have only a word number. To address characters, a C implementation had to synthesize byte addresses by adding extra bits to the address and generating extra instructions to manipulate the word data.
The size of the alignment is a bit tricky to figure out since it depends on a combination of the platform (different CPU architectures have different alignment requirements), toolchain/ABI, and any unusual commands/configurations (e.g. #pragma pack or equivalent).
If I had to guess with reasonable assumptions but no information, it would be plausible that there are two bytes of padding regardless of whether this was a 32-bit or 64-bit system. Two bytes of padding places the offset of ptr at 4+10+2=16, which satisfies both a four-byte and an eight-byte alignment.
It will be dependent on one's architecture but try it out
#include <stdio.h>
struct list {
int key;
char name[10];
struct list* ptr;
};
int main(void) {
printf("Size of struct is %d\n", sizeof(struct list));
struct list the_list;
printf("struct is at address %p\n", &the_list);
printf("key is at address %p\n", &the_list.key);
printf("name is at address %p\n", &the_list.name);
printf("ptr is at address %p\n", &the_list.ptr);
return 0;
}
When I ran this I got
Size of struct is 24
struct is at address 0x7ffcf32ad210
key is at address 0x7ffcf32ad210
name is at address 0x7ffcf32ad214
ptr is at address 0x7ffcf32ad220
showing that of the 24 bytes total, the first 4 bytes were for key at the beginning of the memory block, the next 12 for name, and then the final 8 were for ptr. Notice there were 2 bytes of padding between name and ptr.
But this may differ on different architectures. As always, best to try things out!
The size of a pointer is constant. It doesn't depend on the size of the structure it points to.
For additional information on the size of pointers, take a look here
Your structure will start with four bytes for key (because int is four bytes in your C implementation) and ten bytes for name. (The C standard would allow a C implementation to insert padding between key and name, but there is no need for it.)
Pointers are commonly four or eight bytes in modern systems, but they can be other sizes. They can even be different sizes in different C implementations on the same system. So ptr will likely take four or eight bytes in your C implementation.
Pointers may require alignment, such as requiring four-byte alignment for a four-byte pointer. In this case, there will be two bytes of padding after name and before ptr. That is because the structure has 14 bytes in key and name, so, to bring that up to a multiple of four, two bytes of padding are needed. (Again, the C standard allows an implementation to insert more padding, but it is not needed.)
I was studying the book "Data Structure and algorithms made easy" and but I got confused while learning "Comparing Linked Lists and Unrolled Linked list"...
what is overhead?
Why he is only stating 8 bytes of overhead for 100 elements array?
Overhead is all the stuff that is not part of the data that you want to store. Like the pointers to the next and previous element.
The block list is a list of arrays. Each array contains a number of elements. In principle your entire list could consist of a single block node with an array of all your elements. So less overhead.
It's a bit confusing that head in LinkedBlock points to a ListNode - it should point to whatever the data is (without the prev and next pointers).
I think the book contains a serious error in the definition of struct LinkedBlock. Let's get back to that later and start with:
what is overhead?
The struct ListNode is designed for storing one integer but besides the integer each node has two pointers. So for each node you'll need to allocate 1 integer + 2 pointers. Let's assume 4 byte integer and 4 byte pointer. So each node will require 4 + 2x4 = 12 bytes. So in order to store 1 item of your real data (aka 1 integer) you need to allocate 12 bytes. You have wasted 8 bytes on pointers. These 8 "wasted" bytes are called overhead. They are used for bookkeeping only - not for data.
But it get worse than that... When allocating dynamic memory (which you normally do when using linked list) there are some additional overhead. The allocator may need a little extra memory for every malloc to store information about the malloc. Another issue is that malloc ed memory may aligned to some fixed block size (e.g. 16 or 32 byte) so if you allocate 20 byte there is no way to use the remaining 12 bytes - they are wasted. This is what the book calls "allocation overhead". The "allocation overhead" is system dependent but the book assumes 8 extra overhead bytes from each malloc.
So now each malloc 'ed struct ListNode takes up:
4 bytes for the integer
8 bytes for 2 pointers
8 bytes for allocation overhead
A total of 20 bytes where 4 bytes is for your data and 16 bytes are overhead. So for each integer you need to store, you'll need 20 bytes. And if you want to store 1000 integers, you end up wasting 16kb on overhead in order to store 4kb of data.
Now back to the struct LinkedBlock. In the book it looks like this:
struct LinkedBlock {
struct LinkedBlock *next;
struct LinkedNode *head;
int nodeCount;
};
I'm pretty sure there is a mistake in the book and that it should look like this instead:
struct LinkedBlock {
struct LinkedBlock *next;
int *dataArray;
int nodeCount;
};
The way to use this is something like:
struct LinkedBlock pNode = malloc(sizeof(struct LinkedBlock));
pNode->dataArray = malloc( 100 * sizeof(int) );
The first malloc requires 4 + 4 + 4 + 8 = 20 bytes. (pointer, pointer, int, allocation overhead)
The second malloc requires 4 * 100 + 8 = 408 bytes. (100 int, allocation overhead)
So a total of 428 bytes.
However, since the malloc'ed data can hold 100 integers (corresponding to 400 bytes), your overhead is only 28 bytes. In other words - in average you use 4.28 bytes for each integer. Compare that to the first method that required 20 bytes for each integer.
Why he is only stating 8 bytes of overhead for 100 elements array?
That was because the array was allocated in a single call and each malloc call is assumed to have 8 bytes allocation overhead.
In normal linked list, 1 node have 1 element and 2 pointer (8 bytes), 2 pointer is overhead since it's not your data. In unrolled linked list, 1 node have 100 element and 2 pointer (8 bytes), hence 8 bytes overhead for 100 element.
I'm messing around with Linked List type data structures to get better with pointers and structs in C, and I don't understand this.
I thought that malloc returned the address of the first block of memory of size sizeof to the pointer.
In this case, my node struct looks like this and is 16 bytes:
typedef struct node{
int index;
struct node* next;
}node;
I would expect that if I try to do this: node* root = malloc(sizeof(int))
malloc would allocate only a block of 4 bytes and return the address of that block to the pointer node.
However, I'm still able to assign a value to index and get root to point to a next node, as such:
root->index = 0;
root->next = malloc(sizeof(node));
And the weirdest part is that if I try to run: printf("size of pointer root: %lu \n", sizeof(*root));
I get size of pointer root: 16, when I clearly expected to see 4.
What's going on?
EDIT: I just tried malloc(sizeof(char)) and it still tells me that *root is 16 bytes.
There is a few things going on here, plus one more that probably isn't a problem in this example but is a problem in general.
1) int isn't guaranteed to be 4 bytes, although in most C compiler implementations they are. I would double check sizeof(int) to see what you get.
2) node* root = malloc(sizeof(int)) is likely to cause all sorts of problems, because sizeof(struct node) is not the same as an int. As soon as you try to access root->next, you have undefined behavior.
3) sizeof(struct node) is not just an int, it is an int and a pointer. Pointers are (as far as I know, someone quote the standard if not) the same size throughout a program depending on how it was compiled (32-bit vs 64-bit, for example). You can easily check this on your compiler with sizeof(void*). It should be the same as sizeof(int*) or sizeof(double*) or any other pointer type.
4) Your struct should be sizeof(int) + sizeof(node*), but isn't guaranteed to be. For example, say I have this struct:
struct Example
{
char c;
int i;
double d;
};
You'd expect its size to be sizeof(char) + sizeof(int) + sizeof(double), which is 1 + 4 + 8 = 13 on my compiler, but in practice it won't be. Compilers can "align" members internally to match the underlying instruction architecture, which generally will increase the structs size. The tradeoff is that they can access data more quickly. This is not standardized and varies from one compiler to another, or even different versions of the same compiler with different settings. You can learn more about it here.
5) Your line printf("size of pointer root: %lu \n", sizeof(*root)) is not the size of the pointer to root, it is the size of the struct root. This leads me to believe that you are compiling this as 64-bit code, so sizeof(int) is 4, and sizeof(void*) is 8, and they are being aligned to match the system word (8 bytes), although I can't be positive without seeing your compiler, system, and settings. If you want to know the size of the pointer to root, you need to do sizeof(node*) or sizeof(root). You dereference the pointer in your version, so it is the equivalent of saying sizeof(node)
Bottom line, is that the weirdness you are experiencing is undefined behavior. You aren't going to find a concrete answer, and just because you think you find a pattern in the behavior doesn't mean you should use it (unless you want impossible to find bugs later that make you miserable).
You didn't mention what system (M$ or linux, 32bit or 64bit) but your assumptions about memory allocation are wrong. Memory allocations are aligned to some specified boundary to guarantee all allocations for supported types are properly aligned - typically it is 16 bytes for 64bit mode.
Check this - libc manual:
http://www.gnu.org/software/libc/manual/html_node/Aligned-Memory-Blocks.html
The address of a block returned by malloc or realloc in GNU systems is
always a multiple of eight (or sixteen on 64-bit systems). If you need
a block whose address is a multiple of a higher power of two than
that, use aligned_alloc or posix_memalign. aligned_alloc and
posix_memalign are declared in stdlib.h.
There's a few things happening here. First, C has no bounds checking. C doesn't track how much memory you allocated to a variable, either. You didn't allocate enough memory for a node, but C doesn't check that. The following "works", but really it doesn't.
node* root = malloc(sizeof(int));
root->index = 0;
root->next = malloc(sizeof(node));
Since there wasn't enough memory allocated for the struct, someone else's memory has been overwritten. You can see this by printing out the pointers.
printf("sizeof(int): %zu\n", sizeof(int));
printf("root: %p\n", root);
printf("&root->index: %p\n", &root->index);
printf("&root->next: %p\n", &root->next);
sizeof(int): 4
root: 0x7fbde5601560
&root->index: 0x7fbde5601560
&root->next: 0x7fbde5601568
I've only allocated 4 bytes, so I'm only good from 0x7fbde5601560 to 0x7fbde5601564. root->index is fine, but root->next is writing to someone else's memory. It might be unallocated, in which case it might get allocated to some other variable and then you'll see weird things happening. Or it might be memory for some existing variable, in which case it will overwrite that memory and cause very difficult to debug memory problems.
But it didn't go so far out of bounds so as to walk out of the memory allocated to the whole process, so it didn't trigger your operating system's memory protection. That's usually a segfault.
Note root->next is 8 bytes after root->index because this is a 64 bit machine and so elements of a struct align on 8 bytes. If you were to put another integer into the struct after index, next would still be 8 bytes off.
There's another possibility: even though you only asked for sizeof(int) memory, malloc probably allocated more. Most memory allocators do their work in chunks. But this is all implementation defined, so your code still has undefined behavior.
And the weirdest part is that if I try to run: printf("size of pointer root: %lu \n", sizeof(*root)); I get size of pointer root: 16, when I clearly expected to see 4.
root is a pointer to a struct, and you'd expect sizeof(root) to be pointer sized, 8 bytes on a 64 bit machine to address 64 bits of memory.
*root dereferences that pointer, sizeof(*root) is the actual size of the struct. That's 16 bytes. (4 for the integer, 4 for padding, 8 for the struct pointer). Again, C doesn't track how much memory you allocated, it only tracks what the size of the variable is supposed to be.
typedef struct Node {
int data;
struct Node *next;
} node;
pointer->next = (node*)malloc(sizeof(node));
How many bytes of memory are dynamically given to pointer->next in the above code. For (int*)malloc(sizeof(int)), 2 bytes are given. Likewise how many for node?
Malloc will dinamically assign the size of "node".
Node is a struct and the size of every struct depends on the size of every element inside the struct.
In this case, the size of node will be: size of int + size of struct Node*
(If the result is not multiple of 2, it will be padded for architecture reasons)
Your device has an architecture of 2 bytes, and for that reason, the size of the structs can only be 2, 4, 6, 8 etc...
The size of int depends on the target you are working on. Since your architecture is 16 bits, the size of int is 2 bytes.
About. the size of struct Node *, you need to know that EVERY pointer data types have exactly the same size, it doesn't matter the data type their are pointing to. And that size also depends on the architecture. Again, your architecture is 16 bits and that's why the size of struct node * is 2 bytes.
size of int = 2.
size of struct node * = 2
Total memory assigned by malloc = 2 + 2 = 4
First, a suggestion: rewrite
pointer->next=(node*)malloc(sizeof(node));
as
pointer->next = malloc( sizeof *pointer->next );
You don't need the cast (unless you're working on a pre-ANSI implementation, in which case God help you), and using the dereferenced target as the operand of sizeof means you don't have to specify the type, potentially saving you some maintenance heartburn.
Also, a little whitespace goes a long way (although you don't need to put whitespace around the function arguments - that's my style, some people don't like it, but it makes things easier for me to read).
How much bytes of memory is dynamically given to pointer->next
It will be at least as big as sizeof (int) plus sizeof (struct Node *), and potentially may be bigger; depending on your platform, it could be as small as 4 bytes or as large as 16. C allows for "padding" bytes between struct members to satisfy alignment requirements for the underlying architecture. For example, a particular architecture may require that all multi-byte objects be aligned on addresses that are multiples of 4; if your data member is only 2 bytes wide, then there will be 2 unused bytes between it and the next member.
Without knowing a lot about your system, we just can't tell you. You can take that same code and try it on multiple compilers, and you'll get different answers. You have to check yourself, using sizeof(node) or sizeof(struct Node) (I think either syntax works, but just in case).
I have been reading data structure alignment articles but I'm getting nowhere. Perhaps things are just too complicated for me to understand. I also came across data structure padding which is also necessary to align data. How do I add a data structure padding to struct usb_ep? Also how do I make sure that whenever I perform kmalloc the data to be read should be at a memory offset which is some multiple of 4?
Regarding alignment, kmalloc will align the structures properly. If you have an 4byte variable, it will be 4bytes aligned, if you have an 8byte vaiable, it will be 8bytes aligned. Understanding alignment is the reason why padding is needed.
What you dont want to get is garbade padding between the variables in your struct. You can do that with the pragma pack directive (probably easiest) or by adding the padding manually.
Example
struct usb_ep
{
short a; /* 2 bytes*/
int b; /* 4 bytes*/
short c; /* 2 bytes*/
};
The size of all the elements is 8bytes, but due to alignment requirements, the size will be 12bytes. Memory layout would be like this:
short a - 2 bytes
char pad[2] - 2 bytes of padding
int b - 4 bytes
short c - 2 bytes
char pad[2] - 2 bytes of padding
In order to not get any padding, or increasing the size of the struct, you can rearrange elements in order to satisfy the alignment requirements.
That is having a struct:
struct usb_ep
{
short a; /* 2 bytes*/
short c; /* 2 bytes*/
int b; /* 4 bytes*/
};
Will have the size of 8bytes, and no requirement for adding padding.
This comes from http://minirighi.sourceforge.net/html/kmalloc_8c.html
void * kmemalign (size_t alignment, size_t size)
Allocate some memory aligned to a boundary.
Parameters:
alignment The boundary.
size The size you want to allocate.
Exceptions:
NULL Out-of-memory.
Returns:
A pointer to a memory area aligned to the boundary. The pointer is a aligned_mem_block_t pointer, so if you want to access to the data area of this pointer you must specify the p->start filed.
Note:
Use kfree(void *ptr) to free the allocated block.
The best way to pad fields in a structure is to declare your variables in descending size. So your largest ones first, then down to the smallest.
struct example {
double amount;
char *name;
int cnt;
char is_valid;
};
This doesn't always end up with logically connected items in the structure, but will typically give the most compact and easily accessible memory usage.
You can use use padding bytes in your struct declarations, but they clutter up the code, and do not guarantee compact structures. A compiler may align every byte on a 4 byte boundary, so you might end up with
struct example2 {
char a;
char padding1[3];
char b;
char padding2[3];
};
taking 4 bytes for a, 4 bytes for padding1, 4 bytes for b, and 4 bytes for padding2. Some compilers allow you to specify packed structures which would yield the correct result in this case. Usually I just declare the fields from largest to smallest types and leave it at that. If you need to share memory between two langages/compilers, then you need to make sure the structs align identically in memory.