Например, у меня есть эта структура
struct A {
float x;
float y;
float z;
};
Могу ли я это сделать? A a; float* array = (float*)&a;
И использовать массив как float?
Например, у меня есть эта структура
struct A {
float x;
float y;
float z;
};
Могу ли я это сделать? A a; float* array = (float*)&a;
И использовать массив как float?
Нет, приведение типа struct
в массив не будет работать. Составителям разрешено добавлять дополнения между участниками.
Массивы не имеют дополнения между членами.
Примечание: нет ничего, что помешало бы вам от кастинга, однако, используя значение после результатов листинга в поведении undefined.
В практическом смысле да, вы можете сделать это, и он будет работать во всех используемых в основном архитектурах и компиляторах.
См. "Типичное выравнивание C структур на x86" в Википедии.
Подробнее:
floats - 4 байта, и никакие дополнения не будут вставлены (практически во всех случаях).
Кроме того, большинство компиляторов имеют возможность указывать упаковку структур, и вы можете обеспечить, чтобы никакое дополнение не было вставлено (т.е. пакет #pragma из visual studio)
Массивыгарантируют непрерывность в памяти.
Можете ли вы гарантировать, что он будет работать во всех ЦП в мире со всеми компиляторами? Нет.. но я определенно хотел бы увидеть платформу, где это не удается:)
EDIT: добавление static_assert(sizeof(A) == 3*sizeof(float))
сделает этот код не компилируемым, если есть байты заполнения. Таким образом, вы будете уверены, что он работает, когда он компилируется.
Это строгое нарушение псевдонимов, простое и простое. Любой доступ с этим указателем к любому элементу, кроме первого, - это поведение undefined в вашем случае. И в более сложных случаях это просто обычное поведение undefined, независимо от того, к какому элементу вы обращаетесь.
Если вам нужен массив, используйте массив. std::array
также имеет перегрузку для std::get
, поэтому вы можете использовать это имя каждого отдельного элемента массива:
using A = std::array<float, 3>;
enum AElement { X, Y, Z };
int main() {
A a;
get<X>(a) = 3.0f; // sets X;
float* array = a.data(); // perfectly well defined
}
Для g++ вы можете использовать атрибут для своей структуры, например:
struct A {
float x;
float y;
float z;
}__attribute__((__packed__));
Отключает выравнивание структуры.
Вы можете сделать это, пока компилятор не начнет оптимизировать, а затем все будет не так.
Доступ к любому, но первому элементу структуры с помощью указателя на первый элемент, - это поведение undefined. "Undefined поведение" означает, что все может случиться. Компилятор может предположить, что поведение undefined отсутствует.
Есть много последствий, которые компилятор может вывести из этого: если компилятор знает, что ваш float * указывает на первый элемент структуры, тогда он может вывести, что каждый индекс этого массива равен 0 (поскольку что-то еще есть undefined). Если компилятор этого не знает, то он может вывести, что указатель массива не может указывать на структуру, а изменение элементов массива не может изменить элементы структуры и наоборот.
Вы видите, как это пойдет не так?