what is the relation between 32 bit and 4GB memory? [duplicate] - c

This question already has answers here:
how much memory can be accessed by a 32 bit machine?
(7 answers)
Closed 6 years ago.
I understand that a 32 bit OS can have 2^32 memory location and 2^32 is almost equal to 4 billion. But why the memory is 4GB? 1 byte is 8 bits and on each memory location there are 4 bytes = 32 bit. So 2 ^ 32 times 4 should equal to 4 * 4 * (2 ^ 30) = 16 GB?

2^32 bytes = 4294967296 bytes = 4194304 KB = 4096 MB = 4GB.
A 32-bit OS uses 32-bit pointers. The largest value that can point to is 2^32 - 1. So a 32-bit OS can only see 4GB of memory.

Related

Nested struct memory layout in c

I have a stuct a of size 16 bytes and another struct b which contains a.
Why is struct b of size 40 bytes? Where is the additional padding exactly?
typedef struct {
} a;
typedef struct {
a x;
} b;
The struct a has 4-byte alignment since that's the largest alignment of any of its members (i.e. float).
From there, the fields of b are laid out with the following offsets:
w: 0
padding: 1 - 3
x: 4 - 19
padding: 20 - 23
y: 24 - 31
z: 32 - 33
padding: 34 - 39
The member with the largest alignment is y which has 8-byte alignment. This results in 4 bytes of padding between x and y, as well as 6 bytes of padding at the end.
The padding can be minimized by moving z to between w and x. Then you would have:
w: 0
padding: 1
z: 2 - 4
x: 4 - 19
padding: 20 - 23
y: 24 - 31
For a total size of 32.
Alignment is of course entirely up to the implementation, but this is what you'll most likely see. The Lost Art of C Structure Packing goes into this in much more detail.
The algorithm compilers typically use to lay out structures is described in this answer.
For your structure a and characteristics typical in current C implementations (described below):
The char w has an alignment requirement of 1 byte, so it needs no padding and is placed at offset 1. It occupies 1 byte.
The float x has an alignment requirement of 4 bytes, so 3 bytes are needed to bring the current offset from 1 byte to 4 bytes. Then it occupies 4 bytes, giving us 8 total so far.
The short int y has an alignment requirement of 2 bytes, so it needs no padding from the current offset of 8 bytes. It occupies 2 bytes, bringing the total to 10.
The float z has an alignment requirement of 4 bytes, so it needs 2 bytes to bring the offset from 10 bytes to 12 bytes. It occupies 4 bytes, bringing the total to 16.
The alignment requirement of the structure is 4 bytes (the strictest alignment requirement of its members), and the current total is 16 bytes, which is already a multiple of 4, so no padding at the end is needed.
Thus the size of a is 16 bytes.
For your structure b:
The char w has an alignment requirement of 1 byte, so it needs no padding and is placed at offset 1. It occupies 1 byte.
The a x has an alignment requirement of 4 bytes, so 3 bytes of padding are needed to bring the offset from 1 byte to 4 bytes. It occupies 16 bytes, bringing the total to 20.
The double y has an alignment requirement of 8 bytes, so 4 bytes of padding are needed to bring the offset from 20 bytes to 24. It occupies 8 bytes, bringing the total to 32.
The short int z has an alignment requirement of 2 bytes, so no padding is needed from the current offset of 32 bytes. It occupies 2 bytes, bringing the total to 34.
The alignment requirement of the structure is 8 bytes (the strictest alignment requirement of its members), so 6 bytes of padding is needed to bring the total size from 34 bytes to 40.
Thus the size of b is 40 bytes.
The characteristics used are:
char has size 1 byte and alignment requirement 1 byte. This is a fixed property of the C standard.
short int has size 2 bytes and alignment requirement 2 bytes.
float has size 4 bytes and alignment requirement 4 bytes.
double has size 8 bytes and alignment requirement 8 bytes. (Having an alignment requirement of 4 bytes instead of 8 would not be very weird; hardware might load and store doubles in 32-bit chunks and not care whether either of them were 8-byte aligned.)
The C implementation does not use more padding or stricter alignment than required by the sizes and alignment requirements of structure members. (This is not mandated by the C standard, but there is generally no reason to do otherwise.)
You seem to understand why the size of a is 16 bytes, and I'll also assume that you see why a has an alignment requirement of 4 bytes (see the note about arrays in the discussion below on the alignment of b). From that, we can see that, in b, we will have 3 bytes of padding between w and x.
Now, on your platform (as on many/most), a double has a size and alignment requirement of 8 bytes – so, after the 20 bytes up to the end of x (1 for w, 3 for padding and 16 for x), we need to add 4 bytes padding between x and y, to align that double. Thus, we have now added 12 bytes to our total, giving a running size (up to y) of 32 bytes.
The z member takes another 2 bytes (running size of 34) but, as the alignment requirement of the overall b structure must be 8 bytes (so that, in an array of such, every element's y will remain properly aligned), we need a further 6 bytes to reach a size (40) that is a multiple of 8.
Here is a breakdown of the memory layout:
typedef struct {
char w; // 1 byte: total = 1
// 3 bytes padding: total = 4
float x; // 4 bytes: total = 8
short int y;// 2 bytes: total = 10
// 2 bytes padding: total = 12
float z; // 4 bytes: TOTAL = 16
} a;
typedef struct {
char w; // 1 byte: total = 1
// 3 bytes padding: total = 4
a x; // 16 bytes: total = 20
// 4 bytes padding: total = 24
double y; // 8 bytes: total = 32
short int z;// 2 bytes: total = 34
// 6 bytes padding: TOTAL = 40
} b;

Why does this malloc wrapper do this to the size of the requested memory? size = (size + 3) & ~3;

I'm looking through DOOM source code and I found this line.
void *
Z_Malloc
(int size,
int tag,
void *user) {
int extra;
memblock_t *start;
memblock_t *rover;
memblock_t *newblock;
memblock_t *base;
size = (size + 3) & ~3; // Why is it doing this?
...
I see sizeof used a lot to create byte offsets, but I've never seen this.
I understand the caller of this function wants some memory allocated, but I'm at a loss why it would manipulate the size like this.
What is it doing?
size = (size+3) & ~3 rounds the size up to the nearest multiple of 4.
It does this so that all blocks are a multiple of 4 bytes long and every block starts at an address that is a multiple of 4.
This is necessary so that the placement of ints and pointers inside the block can be aligned to fit into single memory words, which makes accessing them more efficient. Some processors actually require it.
To see how the rounding works, lets say that size = 4x-a, where 0 <= a <= 3. We have:
size+3 = 4x + (3-a), where 3-a is also between 0 and 3.
~3 is a bit mask that includes all bits except 20 and 21, so the & operation will leave just the multiple of 4:
(size+3)&~3 = 4x
If you run this it will be obvious:
for(int i=0; i<30; i++)
printf("%d ", (i+3) & ~3);
Output:
0 4 4 4 4 8 8 8 8 12 12 12 12 16 16 16 16 20 20 20 20 24 24 24 24 28 28 28 28 32
It rounds up to nearest 4.
It's done like this. Performing x = x & ~3 will set the two least significant bits of x to zero. If we assume 8-bit numbers for simplicity, a 3 will be stored as 00000011, which means that ~3 will be 11111100, so performing a logical and with this number will set the last two bits to zero. This itself is a rounding down to nearest four, because 4 binary is 100. If you add 3 first it will be a rounding up instead.

adjusting memory alignment in a struct

I am aware of the memory alignment in structure but I am stumped at this implementation I came across in a project I am working on.
struct default {
uint8_t variable[((sizeof(struct dummyStructure) + 3) /4)*4] // Align on 32 bit boundary
}
It is more like a black box testing for me at the moment because I dont have access to the functions, but can anyone explain the math used here to cause this alignment to happen.
The answer to your question is that, by adding 3 to the size of dummyStructure and by taking the integer part of the result of the division by 4 to multiply by 4, you will either have:
The exact size of dummyStructure, if it is aligned to 32 bits (or any multiple of it, such as 64 bits).
Or the first multiple of 32 bits greater than the size of dummyStructure.
Therefore it will always yield a 4 bytes divisible number (32 bits alignment).
Example:
If the size of dummyStructure is 8 bytes, the result would be ((8 + 3)/4)*4 = 8.
Now if the size of dummyStructure is, lets say 11, the result would be ((11 + 3)/4)*4 = 12.
I'm just wondering why the developer decided for this, though, since dummyStructure should be always aligned according to the processor architecture.
You can decompose it:
uint8_t variable[((sizeof(struct dummyStructure) + 3) /4)*4]
You have two cases - sizeof dummyStructure is evenly dividable by 4 or not.
Example:
(sizeof(struct dummyStructure) = 12
(12 + 3) / 4 = 15 / 4 = 3
3 * 4 = 12
so return original size
(sizeof(struct dummyStructure) = 13
(13 + 3) / 4 = 16 / 4 = 4
4 * 4 = 16
so return next size evenly dividable by 4
(sizeof(struct dummyStructure) = 15
(15 + 3) / 4 = 18 / 4 = 4
4 * 4 = 16
as above
(sizeof(struct dummyStructure) = 16
(16 + 3) / 4 = 19 / 4 = 4
4 * 4 = 16
so return original size again
(sizeof(struct dummyStructure) = 17
(17 + 3) / 4 = 20 / 4 = 5
5 * 4 = 20
so return next size evenly dividable by 4
In reality this code does not align variable at 32bit address! It only allocates enough space in array to allow put there dummyStructure alligned manually.
This solution is really bad.
IMHO better solutions (of course depends what happens in code):
1) since C11
struct defaultx
{
alignas(4) int variable[sizeof(struct dummyStructure)];
};
2) gcc or clang specific
struct defaultx
{
int variable[sizeof(struct dummyStructure)];
} __attribute__((aligned(4)));
will make sure variable is aligned to 4 bytes;

Size of a structure in C [duplicate]

This question already has answers here:
Why isn't sizeof for a struct equal to the sum of sizeof of each member?
(13 answers)
Closed 6 years ago.
I was trying to find out the sizeof a structure, which I thought should show up as 24 bytes on my 64 bit Mac OS, instead it was shown as 32 bytes. what am i missing?
#include<stdio.h>
int main() {
struct Test{
int a;
int *b;
char *c;
float d;
}m;
int size = sizeof(m);
printf("%d\n",size);
}
Any of the field is aligned to its minimal alignment which is 4 for ints and floats and 8 for pointers. There will be padding and memory unused before such alignment. The full structure is aligned to 16 due to SSE requirements:
a: offset 0
b: offset 8 (4 bytes padding before)
c: offset 16
d: offset 24
padding 4 bytes to align to 16 bytes.
Alignment. 4 bytes int, padding 4 bytes, 8 bytes pointer, eight bytes pointer, 4 bytes float, 4 bytes padding.

Memory locations, and ranges

Say I have a struct:
struct guitar{
long guitarID;
short brand:3;
short strings: 6;
short price;
}x[5][5]; //Thanks chux
If the address of x is 0xaaa and memory is aligned at multiples of 4 then what would the address be at x[1]?
The other thing I want to know is what the range of numbers between brand and strings are now that they are affected by a bitfield?
Assuming long 8 bytes, short 2 bytes and memory is 4 bytes aligned size of struct is 8 byte + 3 bit + 6 bit + 2 byte = 8 + 4 = 12 bytes.
x[1] is nothing but &x[1][0].
If x is 0xaaa , x[1] is 0xaaa + (5 * 12) = 0xaaa + 60.
So x[1] is 60 bytes away from x.
Let's try to compute it. The first thing you need to know the size of the struct. Since the size is implementation dependent let's consider a 32-bit machine.
The first member of your structure, guitarID, has 4 bytes. Then, you have 3 bits in brand, 6 bits in strings. These 2, along with padding, make up another 2 bytes. And then, you have another 2 bytes in price. In total, your structure occupies 8 bytes.
Now, let's see how your array is stored. You have a matrix of 5 by 5 elements. In memory, it is stored linearly, like this:
x[0][0] x[0][1] x[0][2] x[0][3] x[0][4] x[1][0] x[1][1] x[1][2] x[1][3]
and so on. I don't know exactly what you mean by x[1], but I assume that you're interested in the address of x[1][0]. You can see that it has before it 5 elements, which means that is has an address with 5 * 8 = 40 bytes higher than the address of the first element. I cannot give you an absolute address as an answer, since 0xaaa which you mentioned as an address for the first element is not word aligned.

Resources