Экспериментируя с языком C, я понял, что могу «назвать» размеры матрицы с помощью объединения.
typedef union {
float a[2][10];
struct {
float a_0[10];
float a_1[10];
};
} Matrix_t;
void main(void) {
Matrix_t foo = {.a[1][5] = 42.0f};
assert(42.0f == foo.a_1[5]); // it works !
}
Я знаю, что struct и union могут дополняться в зависимости от архитектуры, но я не уверен в их взаимодействии при использовании вместе с массивами.
Есть ли способ гарантировать во время компиляции, что расположение памяти будет действительным? (Я готов использовать расширение gcc/clang, если это необходимо)
Может быть, что-то вроде этого?
_Static_assert(sizeof((Matrix_t){0})==sizeof(float[2][10]));
Привет @TedLyngmo, спасибо за ответ. Допустим, для скорости компилятор решает добавить float a_0[10]; внезапно a_1[0] больше не будет совпадать с a[1][0]; взлом кода.
Я понимаю. Да, в этом случае текущее статическое утверждение должно помочь. Примечание: не все компиляторы C принимают void main(void). Если вам нужна портативность, используйте int main(void)
Вы должны знать, что такое использование объединений несовместимо с C++.
Спасибо @n.m.couldbeanAI (кстати, отличное имя). Да, я знаю, что каламбур типа объединения не определен в C++. Но ты совершенно прав; это стоит учитывать.





Макрос offsetof можно использовать:
#include <assert.h>
#include <stddef.h> // for offsetof
typedef union {
float a[2][10];
struct {
float a_0[10];
float a_1[10];
};
} Matrix_t;
_Static_assert(offsetof( Matrix_t, a[1][5] ) == offsetof( Matrix_t, a_1[5] ));
int main()
{
}
интересный подход! Тем более, что offsetof становится переносимым в c23.
Я не уверен, что вы подразумеваете под «гарантией во время компиляции того, что расположение памяти будет действительным», но вы наверняка можете использовать
_Static_assertдля подтверждения размера во время компиляции. Я также не понимаю, почему вы используетеsizeof((Matrix_t){0})вместо простоsizeof(Matrix_t)илиsizeof foo.