Memcpy или присвоение структуры?

У меня есть следующий код, и я не уверен, следует ли использовать выравнивание структуры или memcpy для копирования структуры A в пользовательский массив символов/байтов «стека».

Есть ли что-то выгодное/недостаточное в следующих двух вариантах кода или в чем-то, что совершенно неправильно?

Нужная структура/функции.

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;
    }
}

Вариант 1: Назначение структуры

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] */
}

Вариант 2: память

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] */
}

Является ли вариант 1 даже назначением структуры?

Приведут ли оба варианта к одинаковому заполнению и выравниванию?

Повлияет ли порядок байтов целевой архитектуры на вариант 1?


person Michael    schedule 07.10.2013    source источник
comment
Выполнение присваивания структуры может привести к тому, что ваш компилятор выдаст неявный вызов memcpy. Почему тебя это волнует?   -  person Carl Norum    schedule 08.10.2013
comment
Я читал здесь, что назначения структур становятся более сложными, когда задействованы указатели/массивы. Я даже не уверен, является ли вариант 1 назначением структуры или нет. Я надеюсь на разъяснения по этому поводу.   -  person Michael    schedule 08.10.2013


Ответы (1)


Не думаю, что это можно назвать struct заданием. Вы назначаете отдельные поля.

struct в вашем случае, когда вас просто интересует инициализация объекта в стеке, который вы «резервируете», можно использовать временный:

struct base tmp = {
       .type = 1,
       .prev = NULL,
       // whatever other fields you want to initialize
};
var->base = tmp;

или даже проще, используя составной литерал:

var->base = (struct base){
       .type = 1,
       .prev = NULL,
       // whatever other fields you want to initialize
};

Оба метода имеют то преимущество, что все поля, которые вы, возможно, забыли, инициализируются 0. Для самой операции копирования пусть компилятор выбирает то, что сочтет нужным разработчик компилятора. Не возитесь с такими вещами, если тщательный бенчмаркинг не покажет вам, что существует реальная проблема.

person Jens Gustedt    schedule 07.10.2013