一種方法是通過(ab)使用x宏。他們允許你減少重複,代價是你的同事可能發生的憤怒。好處是您只需要在一個地方更新項目列表,並且預處理器將自動生成結構和所有必要的元數據。
I.e.你定義一個簡單的像這樣的條目列表,其中FILE_ENTRY
是沒有明確的規定:
#define X_FILE_LIST(X_FILE_ENTRY) \
X_FILE_ENTRY(radiation_insolation, 7) \
X_FILE_ENTRY(radiation_radiation, 5) \
X_FILE_ENTRY(winds, 9) \
X_FILE_ENTRY(pressure, 1) \
X_FILE_ENTRY(humidity, 1) \
X_FILE_ENTRY(temperature, 4)
,然後定義FILE_ENTRY(name, len)
如你所願:
// number of entries
#define X_EXPAND_AS_COUNT(name, len) 1 +
const int FILES_count = X_FILE_LIST(X_EXPAND_AS_COUNT) 0;
// struct definition
#define X_EXPAND_AS_FIELD(name, len) FILE_ name[len];
typedef struct {
X_FILE_LIST(X_EXPAND_AS_FIELD)
}
FILES;
// byte offsets of each field
#define X_EXPAND_AS_BYTEOFFSET(name, len) offsetof(FILES, name),
int FILES_byte_offsets[] = {
X_FILE_LIST(X_EXPAND_AS_BYTEOFFSET)
};
// FILE_ offsets of each field
#define X_EXPAND_AS_FILEOFFSET(name, len) offsetof(FILES, name)/sizeof(FILE_),
int FILES_offsets[] = {
X_FILE_LIST(X_EXPAND_AS_FILEOFFSET)
};
// sizes of each array
#define X_EXPAND_AS_LEN(name, len) len,
int FILES_sizes[] = {
X_FILE_LIST(X_EXPAND_AS_LEN)
};
// names of each field
#define X_EXPAND_AS_NAME(name, len) #name,
const char * FILES_names[] = {
X_FILE_LIST(X_EXPAND_AS_NAME)
};
這將擴大到是這樣的:
const int FILES_count = 1 + 1 + 1 + 1 + 1 + 1 + 0;
typedef struct {
FILE_ radiation_insolation[7];
FILE_ radiation_radiation[5];
FILE_ winds[9];
FILE_ pressure[1];
FILE_ humidity[1];
FILE_ temperature[4];
}
FILES;
int FILES_byte_offsets[] = {
((size_t)&(((FILES*)0)->radiation_insolation)),
((size_t)&(((FILES*)0)->radiation_radiation)),
((size_t)&(((FILES*)0)->winds)),
((size_t)&(((FILES*)0)->pressure)),
((size_t)&(((FILES*)0)->humidity)),
((size_t)&(((FILES*)0)->temperature)),
};
int FILES_offsets[] = {
((size_t)&(((FILES*)0)->radiation_insolation))/sizeof(FILE_),
((size_t)&(((FILES*)0)->radiation_radiation))/sizeof(FILE_),
((size_t)&(((FILES*)0)->winds))/sizeof(FILE_),
((size_t)&(((FILES*)0)->pressure))/sizeof(FILE_),
((size_t)&(((FILES*)0)->humidity))/sizeof(FILE_),
((size_t)&(((FILES*)0)->temperature))/sizeof(FILE_),
};
int FILES_sizes[] = { 7, 5, 9, 1, 1, 4, };
const char * FILES_names[] = {
"radiation_insolation", "radiation_radiation",
"winds", "pressure", "humidity", "temperature",
};
然後,您可以使用類似的方法重複它:
for (int i = 0; i < FILES_count; i++)
{
FILE_ * first_entry = (FILE_ *)&files + FILES_offsets[i];
for (int j = 0; j < FILES_sizes[i]; j++)
{
FILE_ * file = first_entry + j;
printf("%s[%d].skip_lines = %d \n",
FILES_names[i],
j,
file->skip_lines);
}
}
這項工作將通過FILES
所有成員進行迭代,並通過每個字段的所有陣列成員:
// output of the program above
radiation_insolation[0].skip_lines = 0
radiation_insolation[1].skip_lines = 0
radiation_insolation[2].skip_lines = 0
radiation_insolation[3].skip_lines = 0
radiation_insolation[4].skip_lines = 0
radiation_insolation[5].skip_lines = 0
radiation_insolation[6].skip_lines = 0
radiation_radiation[0].skip_lines = 0
radiation_radiation[1].skip_lines = 0
radiation_radiation[2].skip_lines = 0
radiation_radiation[3].skip_lines = 0
radiation_radiation[4].skip_lines = 0
winds[0].skip_lines = 0
winds[1].skip_lines = 0
winds[2].skip_lines = 0
winds[3].skip_lines = 0
winds[4].skip_lines = 0
winds[5].skip_lines = 0
winds[6].skip_lines = 0
winds[7].skip_lines = 0
winds[8].skip_lines = 0
pressure[0].skip_lines = 0
humidity[0].skip_lines = 0
temperature[0].skip_lines = 0
temperature[1].skip_lines = 0
temperature[2].skip_lines = 0
temperature[3].skip_lines = 0
這給你帶來實際的「反思」,它可以讓你找到它的名稱的成員:
FILE_ * get_entry_by_name_and_index(FILES * files, const char * name, int idx)
{
// NOTE: no bounds checking/safe string function, etc
for (int i = 0; i < FILES_count; i++)
{
if (strcmp(FILES_names[i], name) == 0)
{
int base_offset = FILES_offsets[i];
return (FILE_ *)files + base_offset + idx;
}
}
return NULL;
}
例如,這將讓指針files.winds[4]
:
FILE_ * item = get_entry_by_name_and_index(&files, "winds", 4);
assert((void*)item == (void*)&files.winds[4]);
你不能。它被稱爲反射,C不支持它。編譯時會丟失變量名稱。 –
你不能。 C沒有[內省](https://en.wikipedia.org/wiki/Type_introspection)或[反思](https://en.wikipedia.org/wiki/Reflection_(computer_programming)),這是需要的這工作。 –
在一個不相關的說明中,如果你在你的程序中使用文件,創建類型名爲FILE_和FILES會導致問題,因爲你有標準的C FILE和你的FILE_和FILES。 。這將是很難閱讀和理解,以及容易犯錯誤。 –