1

次のコードがあり、構造体のアライメントまたは memcpy を使用して構造体 A をカスタムの「スタック」文字/バイト配列にコピーするかどうかがわかりません。

コードの次の 2 つのオプションについて有利/不利な点はありますか、それとも完全に間違っていますか?

必要な構造体/関数。

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

オプション 1 は構造体の代入でもありますか?

両方のオプションで同じパディングと配置になりますか?

ターゲット アーキテクチャのエンディアンはオプション 1 に影響しますか?

4

1 に答える 1

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。コピー操作自体については、コンパイラの設計者が適切と判断したものをコンパイラに選択させます。注意深いベンチマークによって実際の問題があることが示されない限り、そのようなことをいじらないでください。

于 2013-10-07T21:47:46.847 に答える