ここでは、匿名の構造体を使用できます。
#ifndef MYSTRUCT_H
#define MYSTRUCT_H
typedef struct {
int i;
struct {
int j;
} MYSTRUCT_PRIVATE;
// NOTE: Avoid putting public members after private
int k;
} MyStruct;
void test_mystruct();
#endif
プライベートメンバーにアクセスする必要があるファイルでは、MYSTRUCT_PRIVATE
このヘッダーを含める前に空のトークンとして定義します。これらのファイルでは、プライベートメンバーは匿名の構造体にあり、を使用してアクセスできますm.j
が、他のすべての場所では、を使用してのみアクセスできますm.MYSTRUCT_PRIVATE.j
。
#define MYSTRUCT_PRIVATE
#include "mystruct.h"
void test_mystruct() {
// Can access .j without MYSTRUCT_PRIVATE in both
// initializer and dot operator.
MyStruct m = { .i = 10, .j = 20, .k = 30 };
m.j = 20;
}
#include <stdio.h>
#include "mystruct.h"
int main() {
// You can declare structs and, if you jump through
// a small hoop, access private members
MyStruct m = { .i = 10, .k = 30 };
m.MYSTRUCT_PRIVATE.j = 20;
// This will not work
//MyStruct m2 = { .i = 10, .j = 20, .k = 30 };
// But this WILL work, be careful
MyStruct m3 = { 10, 20, 30 };
test_mystruct();
return 0;
}
パブリックメンバーをプライベートメンバーの後に置くことはお勧めしません。withなどのメンバー指定子なしで構造体を初期化しても、{ 10, 20, 30 }
プライベートメンバーを初期化できます。プライベートメンバーの数が変更された場合、これにより、メンバー指定子のないすべての初期化子もサイレントに中断されます。これを回避するには、常にメンバー指定子を使用するのが最善です。
C ++のように自動コンストラクターがないため、構造体、特にプライベートメンバーをゼロ初期化するように設計する必要があります。メンバーが0に初期化されている限り、初期化関数がなくてもメンバーが無効な状態のままになることはありません。メンバー指定子の初期化を除いて、単純に初期化する{ 0 }
ことは安全であるように設計されるべきです。
私が見つけた唯一の欠点は、これがデバッガーやコード補完などを混乱させることです。通常、あるタイプのメンバーのセットが1つのファイルにあり、別のセットが別のファイルにある場合、それらは気に入らないのです。