7

私は C11 と VLA を試していて、不完全な宣言だけでスタック上に構造体変数を宣言しようとしました。目的は、(PIMPL イディオムのように) 内部を表示せずに、構造体型の変数を作成するメカニズムを提供することですが、ヒープ上に変数を作成してポインターを返す必要はありません。また、構造体のレイアウトが変更された場合、構造体を使用するすべてのファイルを再コンパイルしたくありません。

私は次のようにプログラムすることができました:

private.h:

#ifndef PRIVATE_H_
#define PRIVATE_H_

typedef struct A{
    int value;
}A;

#endif /* PRIVATE_H_ */

public.h:

#ifndef PUBLIC_H_
#define PUBLIC_H_

typedef struct A A;

size_t A_getSizeOf(void);

void A_setValue(A * a, int value);

void A_printValue(A * a);

#endif /* PUBLIC_H_ */

実装.c:

#include "private.h"
#include "stdio.h"

size_t A_getSizeOf(void)
{
    return sizeof(A);
}

void A_setValue(A * a, int value)
{
    a->value = value;
}

void A_printValue(A * a)
{
    printf("%d\n", a->value);
}

main.c:

#include <stdalign.h>
#include <stddef.h>

#include "public.h"

#define createOnStack(type, variable) \
    alignas(max_align_t) char variable ## _stack[type ## _getSizeOf()]; \
    type * variable = (type *)&variable ## _stack

int main(int argc, char *argv[]) {
    createOnStack(A, var);

    A_setValue(var, 5335);
    A_printValue(var);
}

このコードをテストしましたが、うまくいくようです。ただし、危険または移植性がなく、パフォーマンスを損なう可能性のあるもの (エイリアシング、アライメントなど) を見落としているかどうかはわかりません。また、C でこの問題に対するより良い (移植可能な) 解決策があるかどうかも知りたいです。

4

2 に答える 2

4

もちろん、これは効果的な型付け規則 (別名厳密なエイリアシング) に違反します。これは、C 言語では、char []その型 (または互換性のある型) を持たないポインターを介して tye のオブジェクトにアクセスすることを許可しないためです。

次のようなコンパイラフラグまたは属性を使用して、厳密なエイリアシング分析を無効にすることができます-fno-strict-aliasing

#ifdef __GNUC__
#define MAY_ALIAS __attribute__((__may_alias__))
#else
#define MAY_ALIAS
#endif

(後者を指摘してくれたR..に感謝します)しかし、そうしなくても、変数の適切な名前を使用して型付きポインターを初期化する限り、実際にはすべて正常に機能するはずです。

個人的には、宣言を次のようなものに単純化します

#define stackbuffer(NAME, SIZE) \
    _Alignas (max_align_t) char NAME[SIZE]

typedef struct Foo Foo;
extern const size_t SIZEOF_FOO;

stackbuffer(buffer, SIZEOF_FOO);
Foo *foo = (void *)buffer;

代替手段は非標準を使用することalloca()ですが、その「機能」には独自の問題があります。

于 2014-08-28T00:24:43.470 に答える