Search code examples
cstructmemcpymemory-alignment

Memcpy or struct assignment?


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?


Solution

  • 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.