3

次のような小さなデータ非表示モジュールがあります。

/** mydata.h */
struct _mystruct_t;
typedef struct _mystruct_t mystruct;

mystruct *newMystruct();
void freeMystruct( mystruct** p );

/** mydata.c */
#include "mydata.h"
struct _mystruct_t {
    int64_t data1;
    int16_t data2;
    int16_t data3;
};
// ... related definitions ... //

ほとんどの場合、これが私が望んでいることです。シンプルですが、構造体には厳密な一貫性要件があり、データ メンバーへのアクセスを提供したくありません。

問題は、クライアント コードで、スタックに割り当てたい別の構造体に構造体を含めたいことです。mystruct*現在、いくつかのクライアント コードで sを解放するためにフープをジャンプしています。a) mystruct はかなり小さいので、すぐに大きくなるとは思いません。b) mystruct を変更した場合にクライアント コードを再コンパイルしなければならないことは問題ではないので、mystruct のサイズを公開したいと思います。 (つまり、ヘッダー内)。

私が検討した2つの可能性:

/** mydata.h */
typedef struct {
    // SERIOUSLY DON'T ACCESS THESE MEMBERS
    int64_t data1;
    int16_t data2;
    int16_t data3;
} mystruct;

ここでの欠点がそれ自体を物語っていると思います。

また

/** mydata.h */
#define SIZEOF_MYSTRUCT (sizeof(int64_t)+sizeof(int16_t)+sizeof(int16_t))
// everything else same as before...

/** mydata.c */
// same as before...
_Static_assert (SIZEOF_MYSTRUCT == sizeof(mystruct), "SIZEOF_MYSTRUCT is incorrect")

もちろん、この値を手動で更新する必要があるため、これは理想的ではないように思われます。また、構造体のアライメントが実際にこれを不正確にする可能性があるかどうか、またはその方法がわからないためです (この質問を書いているときに静的アサートについて考えましたが、部分的に対処していますこの懸念)。

これらのいずれかが優先されますか? または、さらに良いことに、ヘッダーに実際の構造体定義を提供し、後でメンバーにアクセスする機能を何らかの形で隠すための巧妙なトリックはありますか?

4

3 に答える 3

-1

私は調査と検討を重ね、潜在的な答えの 1 つを取り上げ、それを次のレベルに引き上げました。それは私のすべての懸念に対処していると思います。批評してください。

/** in mydata.h */
typedef const struct { const char data[12]; } mystruct;
mystruct createMystruct();
int16_t exampleMystructGetter( mystruct *p );
// other func decls operating on mystruct ...


/** in mydata.c */
typedef union {
    mystruct public_block;
    struct mystruct_data_s {
        int64_t d1;
        int16_t d2
        int16_t d3;
    } data;
} mystruct_data;

// Optionally use '==' instead of '<=' to force minimal space usage
_Static_assert (sizeof(struct mystruct_data_s) <= sizeof(mystruct), "mystruct not big enough");

mystruct createMystruct(){
    static mystruct_data mystruct_blank = { .data = { .d1 = 1, .d2 = 2, .d3 = 3 } };
    return mystruct_blank.public_block;
}

int16_t exampleMystructGetter(mystruct *p) {
    mystruct_data *a = (mystruct_data*)p;
    return a->data.d2;
}

gcc 4.7.3 では、これは警告なしでコンパイルされます。ゲッターを介して作成およびアクセスする簡単なテスト プログラムもコンパイルされ、期待どおりに動作します。

于 2014-10-03T19:32:54.430 に答える