Еще одно использование массива нулевой длины - это именованная метка внутри структуры для помощи при проверке смещения структуры во время компиляции.
Предположим, у вас есть несколько больших определений структур (охватывающих несколько строк кэша), которые вы хотите убедиться, что они выровнены по границе строки кеша как в начале, так и в середине, где она пересекает границу.
struct example_large_s
{
u32 first; // align to CL
u32 data;
....
u64 *second; // align to second CL after the first one
....
};
В коде вы можете объявить их, используя расширения GCC, например:
__attribute__((aligned(CACHE_LINE_BYTES)))
Но вы все же хотите убедиться, что это выполняется во время выполнения.
ASSERT (offsetof (example_large_s, first) == 0);
ASSERT (offsetof (example_large_s, second) == CACHE_LINE_BYTES);
Это сработает для одной структуры, но будет сложно охватить несколько структур, каждая из которых имеет разные имена членов, которые нужно выровнять. Скорее всего, вы получите код, подобный приведенному ниже, где вам нужно найти имена первого члена каждой структуры:
assert (offsetof (one_struct, <name_of_first_member>) == 0);
assert (offsetof (one_struct, <name_of_second_member>) == CACHE_LINE_BYTES);
assert (offsetof (another_struct, <name_of_first_member>) == 0);
assert (offsetof (another_struct, <name_of_second_member>) == CACHE_LINE_BYTES);
Вместо этого вы можете объявить в структуре массив нулевой длины, действующий как именованная метка с согласованным именем, но не занимающий места.
#define CACHE_LINE_ALIGN_MARK(mark) u8 mark[0] __attribute__((aligned(CACHE_LINE_BYTES)))
struct example_large_s
{
CACHE_LINE_ALIGN_MARK (cacheline0);
u32 first; // align to CL
u32 data;
....
CACHE_LINE_ALIGN_MARK (cacheline1);
u64 *second; // align to second CL after the first one
....
};
Тогда будет намного проще поддерживать код утверждения времени выполнения:
assert (offsetof (one_struct, cacheline0) == 0);
assert (offsetof (one_struct, cacheline1) == CACHE_LINE_BYTES);
assert (offsetof (another_struct, cacheline0) == 0);
assert (offsetof (another_struct, cacheline1) == CACHE_LINE_BYTES);