I have the following code and am unsure of whether to use structure alignment or memcpy to copy struct A onto the custom "stack" char/byte array.
Is there anything advantageous/disadvantageous about the following two options of code or anything that is just flat out wrong?
The necessary struct/functions.
struct B {
int type;
struct B *prev;
}
struct A {
struct B base;
int n;
struct B *another;
char name[1]; /* Struct hack */
};
void align(char **ptr, int n) {
intptr_t addr = (intptr_t)*ptr;
if(addr % n != 0) {
addr += n - addr % n;
*ptr = (char *)addr;
}
}
Option 1: Struct Assignment
void struct_assignment() {
char *stack = malloc(400*1000);
char *top_of_stack = stack + 3149; /* Just an example */
struct A *var = (struct A *)top_of_stack;
align((char **)&var, sizeof(struct B)); /* Most restrictive alignment member in struct A */
var->base.type = 1;
var->base.prev = NULL;
var->another = (struct base *)var;
char *name = "test";
var->n = strlen(name) + 1;
strcpy(var->name, name);
top_of_stack = (char*)var + sizeof(*var)+ (var->n - 1); /* -1 for name[1] */
}
Option 2: memcpy
void memcpying() {
char *stack = malloc(400*1000);
char *top_of_stack = stack + 3149; /* Just an example */
struct A var;
var.base.type = 1;
var.base.prev = NULL;
var.another = NULL;
char *name = "test";
var.n = strlen(name) + 1;
strcpy(var.name, name);
char *aligned_ptr = top_of_stack;
align(&aligned_ptr, sizeof(struct B)); /* Most restrictive alignment member in struct A */
memcpy(aligned_ptr, &var, sizeof(var) + (var.n - 1); /* -1 for name[1] */
struct A *var_ptr = (struct A*)aligned_ptr;
var_ptr->another = (struct B *)var_ptr;
top_of_stack = aligned_ptr + sizeof(var)+ (var.n - 1); /* -1 for name[1] */
}
Is option 1 even struct assignment?
Will both options result in the same padding and alignment?
Will the endianness of the target architecture affect option 1?
I don't think that this can be called struct
assignment. You are assigning to the individual fields.
struct
assingment in your case where you are merely interested in initialization of the object on the stack that you are "reserving" could use a temporary:
struct base tmp = {
.type = 1,
.prev = NULL,
// whatever other fields you want to initialize
};
var->base = tmp;
or even more consise by using a compound literal:
var->base = (struct base){
.type = 1,
.prev = NULL,
// whatever other fields you want to initialize
};
Both methods have the advantage of initializing all fields that you
might have forgotten to 0
. The for the copy operation itself, let the compiler chose whatever the compiler designer saw fit. Don't mess around with such things unless some careful benchmarking tells you that there is a real problem.