Declaring multiple structs and overlaying them on already allocated memory - c

I am very new to C/C++, so I know that this question is probably trivial but I don't understand how to proceed. I have allocated blocks of memory that are 512 bytes each like so (Sector is a struct of size 512 bytes):
char* block = (char *) malloc (sizeof(Sector));
I have another struct that is 128 bytes in size:
typedef struct inode {
int fileSize;
int fileType;
int* blockPointer[30];
} inodeFile;
What I want to do is overlay this struct on the block. I need each block to contain 4 inode structs, but each struct may not have any values associated with it until later on in the program. So for example:
((*inodeFile) block)->fileSize = 10;
If I am understanding correctly, this is setting the first 4 bytes of the pointer block to fileSize. I would continue to do this for each field of the struct.
My question is, how can I do this for 4 different inodes? And since there are 4 different inodes, how can I return the values of each field for the different structs? It seems like simply saying block->fileSize wouldn't work because there can be up to four different file sizes.

You can use a union to overlay the blocks on the sectors. Because the fields are of int type or pointer or size 512 there shouldn't be an alignment problem so long as the natural size is 32-bit.
typedef struct {
int fileSize;
int fileType;
int* blockPointer[30];
} inode;
typedef union {
unsigned char bytes[512];
inode block[4];
} sector;
int main()
{
sector thisec;
thisec.bytes[511] = 0;
thisec.block[0].fileSize = 10;
return 0;
}

Related

Save a local variable on a heap without using malloc in C (using sbrk or brk)

I have a struct as follows:
struct
__attribute__((__packed__)) // compiler directive, avoid "gcc" padding bytes to struct
meta_data {
size_t size; // 8 bytes (in 64-bit OS)
char free; // 1 byte ('f' or 'o')
};
The size of the struct is 9 bytes.
I want to use sbrk or brk to allocate 9 bytes on the heap and save a struct on the heap, and return a pointer to the dynamically allocated memory block on heap.
Currently I have something like this:
void *add(size_t size) {
void* returnPointer;
returnPointer = sbrk(9);
struct meta_data newMetadata;
newMetadata.size = size;
newMetadata.free = 'o';
return returnPointer;
}
This function should be able to be used multiple times to add more metadata blocks on the heap.
However, in this case, when the function ends, the local variable newMetadata declared inside the function is also terminated.
How can I keep it on the heap and not lose access to the newMetadata created?
Note: I am not allowed to use malloc for this.
The usual method is to mimic what some malloc packages do. That is, put the meta data at a lower address than what is returned as the "data" pointer.
Here's your code refactored to do that:
#include <unistd.h>
struct meta_data {
size_t size; // 8 bytes (in 64-bit OS)
char free; // 1 byte ('f' or 'o')
// compiler directive, avoid "gcc" padding bytes to struct
} __attribute__ ((__packed__));
void *
add(size_t size)
{
struct meta_data *meta;
void *returnPointer;
meta = sbrk(sizeof(struct meta_data) + size);
meta->size = size;
meta->free = 'o';
returnPointer = meta;
returnPointer += sizeof(struct meta_data);
return returnPointer;
}
Note that most malloc replacements will guarantee that returnPointer is "aligned for any purpose", which usually means aligned to an 8 byte boundary (i.e. the lower 3 bits of returnPointer are 0).
The above code doesn't do that, so it's something you can add [later].

Why size of struct in C increases when passed by reference

I have been trying to understand structs and how their sizes differ based on the order members are declared and how padding and alignment are associated with that.
When I declare the struct like the one you see below, I get the size of memory I expected which is 4 bytes.
typedef struct {
int x;
} GPS;
int main()
{
GPS st;
st.x = 42;
int size;
size = sizeof(st);
printf("\n Size: %d", size);
return 0;
}
But when I pass the struct by reference to a function, the struct increases its size to 8 bytes and I'm not sure why. I read everything about bit alignment and padding but it doesn't seem that has anything with the increase in size.
typedef struct {
int x;
} GPS;
int main()
{
GPS st;
st.x = 42;
printStruct(&st);
return 0;
}
void printStruct(GPS *stptr)
{
int size;
char *ch = (char *)stptr;
size = sizeof(stptr);
printf("Size: %i \n", size);
}
So my question is, why does the struct increase in size when passed by reference?
The size isn't increasing. You're getting the size of something else.
In your printStruct function, stptr has type GPS *, i.e. a pointer to GPS. A pointer to a struct is different from a struct instance, so the sizes don't have to be the same.
Had you used sizeof(*stptr), i.e. the size of what stptr points to, you would have gotten the value you expect.
The pointer is 8 bytes. When you pass by reference you're actually sending a pointer not the actual struct.

sizeof structs and nested structs

I have set up structs in this way.
When I print the sizeof(DATA), I get 16. Why is it 16? I thought it would be 8 as 4 for idx, and 4 for the ptr.
I allocate memory for the STUDENT struct and STATS struct array of size 50. Have I allocated enough memory?
typedef struct {
int idNum;
int classNum;
} STATS;
typedef struct {
STATS * stats;
int currGrade;
}STUDENT;
typedef struct {
STUDENT * ptr;
int idx;
} DATA;
//student_main.c
void function1()
{
DATA d;
func(&d);
}
//student.c
void func(DATA * d)
{
Student * s = malloc(sizeof(STUDENT));
d->ptr = s;
d->ptr->currGrade = 1;
STATS * arr = malloc(sizeof(STATS)* 50);
d->ptr->stats = arr;
d->ptr->stats[0].idNum = 1;
d->ptr->stats[0].classNum = 1;
}
I have set up structs in this way. When I print the sizeof(DATA), I
get 16. Why is it 16? I thought it would be 8 as 4 for idx, and 4 for
the ptr.
Because compiler (may) add padding between/behind struct elements to satisfy alignment constraints. You can read something about data structure alignment here.
In your case of DATA, its 16B because (if your machine is x64)
typedef struct
{
STUDENT * ptr; // 8B pointer
int idx; // 4B int
// 4B padding
} DATA;
I allocate memory for the STUDENT struct and STATS struct array of
size 50. Have I allocated enough memory?
It depends on your needs. You have allocated enough space for 50 structures. Remember to always use sizeof(type) while allocating dynamical memory.
The compiler will pad structures, for example to allow faster access to subsequent elements in 64 bit architectures.
You shouldn't ever need to worry about the numeric value of the size of a struct, as the compiler handles it. Use it only for comparisons, and ignore the absolute value (unless your hobby is reverse engineering the compiler)
It can be 16 for one of two reasons - either You have 32 bit machine and the compiler adds some "space" in Your structure to make the operations faster. You can stop this behavior if You want your structures to be of the exact size, by adding __attribute__ ((__packed__)) to the struct definition. Or You have 64 bit machine with 64 bit pointers and integers. Or a mix of both.
You have allocated enough memory. Doing malloc(x * sizeof(struct xxx)) gives You the confidence.
I recommend reading this excellent article: The Lost Art of C Structure Packing

Why can't we access bits that we pad in structures?

My question is we do padding to align structures.
typedef struct structb_tag
{
char c;
int i;
} structb_t;
Here we use 8 bytes. Why can't we use the 3 bytes that lot?
Why cant we use the 3 bytes
You could.
To do so measure the size your implementation allocates for a struct and then make it a union adding a char-array of exactly the size measured and there you go.
Assuming this
typedef struct structb_tag
{
char c;
int i;
} structb_t;
is created using eight bytes, that is sizeof (structb_t) evaluates to 8, change it to the following
typedef union unionb_tag
{
char bytes[8];
struct
{
char c;
int i;
} structb;
}
More reliable, in terms of portability and also robustness, would be this:
typedef union unionb_tag
{
struct structb_tag
{
char c;
int i;
} structb;
char bytes[sizeof (struct structb_tag)];
}
If you are using GCC and space is the most important thing for you instead of speed (which padding provides) you could just request the compiler to not do the padding, struct __attribute__((__packed__)) mystruct, padding is the way for compiler to align structures in the natural for faster access.
You can always take the pointer to the structure convert it to a byte pointer and access any byte of that structure.This is dangerous way, though.
The padding are implementation dependent, which are not defined by the standard, you cannot not use them as there is no way to reference the padding bytes.
Yes, you can.
typedef struct structb_tag
{
char c;
char pad[3];
int i;
} structb_t;
structb_t test;
test.pad[0] = 'a';
In short, we can use that three bytes.
The reason why we need 3 bytes padding is for memory usage optimization, so the compiler will help us add an gap between c and i. So when you use
typedef struct structb_tag
{
char c;
int i;
} structb_t;
It actually
typedef struct structb_tag
{
char c;
char[3] unseen_members;
int i;
} structb_t;
Accessing these unseen members will not cause any segmentation fault. In the point of view of OS, there's no difference between accessing members declared by programmers explicitly and declared by compiler implicitly.
#include <stdio.h>
#include <string.h>
typedef struct Test {
char c;
int i;
} MyTest;
int main() {
MyTest my_test;
memset(&my_test, 0, sizeof(my_test));
my_test.c = 1;
int* int_ptr = (int *)&my_test.c;
printf("Size of my_test is %lu\n", sizeof(my_test));
printf("Value of my_test.c(char) is %d\n", my_test.c);
printf("Value of my_test.c(int) is %d\n", *int_ptr);
return 0;
}
This gives:
Size of my_test is 8
Value of my_test.c(char) is 1
Value of my_test.c(int) is 1
We can access any byte in the structure using a pointer to that structure and typecasting that pointer to (char *) if we accordingly increment that pointer then we can access any byte but this not good programming skill. Structures are padded with some extra bytes so that an execution of the program can become faster.

Data padding on a 64 bit system discrepancy

This program creates and measures a struct with a pointer (8 bytes) and 3 ints (4 bytes each) and shows there are 4 bytes of data padding.
I don't understand why there are 4 bytes of data padding, either the CPU handles it 8 bytes at a time and there should be another 8 bytes of padding or it handles it 4 bytes at a time and there should be none right?
Or does it stick 2 4 byte values in an 8 byte section of memory and let the CPU split it up at runtime? (This would explain the discrepancy but it seems a bit inefficient to me)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct test {
char *name;
int age;
int height;
int weight;
};
struct test *create(char *name, int age, int height, int weight)
{
struct test *thing = malloc(sizeof(struct test));
thing->name = strdup(name);
thing->age = age;
thing->height = height;
thing->weight = weight;
return thing;
}
void destroy(struct test *thing)
{
free(thing->name);
free(thing);
}
int main(int argc, char *argv[])
{
struct test * t1 = create("bleh",1,2,3);
printf("Sizeof struct: %lu\n",sizeof(struct test));
printf("Sizeof pointer (On 64bit system): %lu\n",sizeof(char *));
printf("Sizeof int: %lu\n",sizeof(int));
destroy(t1);
return 0;
}
Output:
Sizeof struct: 24
Sizeof pointer (On 64bit system): 8
Sizeof int: 4
The entire struct is probably padded at the end, for alignment reasons. This is needed since you might want to have an array of this struct.
The padding you mention makes the struct always end up on an address which is evenly divisible by 8.
The pointer presumably needs to be aligned on 8 bytes. Think about what happens when you form an array of your class, test a[10]. The only way to ensure that a[i].name is aligned on 8 bytes is by padding the class to a multiple of 8 bytes.

Resources