Подтвердить что ты не робот

Могу ли я безопасно преобразовать структуру float в массив float в С++?

Например, у меня есть эта структура

struct  A {
    float x;
    float y;
    float z;
};

Могу ли я это сделать? A a; float* array = (float*)&a; И использовать массив как float?

4b9b3361

Ответ 1

Нет, приведение типа struct в массив не будет работать. Составителям разрешено добавлять дополнения между участниками.

Массивы не имеют дополнения между членами.

Примечание: нет ничего, что помешало бы вам от кастинга, однако, используя значение после результатов листинга в поведении undefined.

Ответ 2

В практическом смысле да, вы можете сделать это, и он будет работать во всех используемых в основном архитектурах и компиляторах.

См. "Типичное выравнивание C структур на x86" в Википедии.

Подробнее:

  • floats - 4 байта, и никакие дополнения не будут вставлены (практически во всех случаях).

  • Кроме того, большинство компиляторов имеют возможность указывать упаковку структур, и вы можете обеспечить, чтобы никакое дополнение не было вставлено (т.е. пакет #pragma из visual studio)

    Массивы
  • гарантируют непрерывность в памяти.

Можете ли вы гарантировать, что он будет работать во всех ЦП в мире со всеми компиляторами? Нет.. но я определенно хотел бы увидеть платформу, где это не удается:)

EDIT: добавление static_assert(sizeof(A) == 3*sizeof(float)) сделает этот код не компилируемым, если есть байты заполнения. Таким образом, вы будете уверены, что он работает, когда он компилируется.

Ответ 3

Это строгое нарушение псевдонимов, простое и простое. Любой доступ с этим указателем к любому элементу, кроме первого, - это поведение 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
}

Ответ 4

Для g++ вы можете использовать атрибут для своей структуры, например:

struct  A {
    float x;
    float y;
    float z;
}__attribute__((__packed__));

Отключает выравнивание структуры.

Ответ 5

Вы можете сделать это, пока компилятор не начнет оптимизировать, а затем все будет не так.

Доступ к любому, но первому элементу структуры с помощью указателя на первый элемент, - это поведение undefined. "Undefined поведение" означает, что все может случиться. Компилятор может предположить, что поведение undefined отсутствует.

Есть много последствий, которые компилятор может вывести из этого: если компилятор знает, что ваш float * указывает на первый элемент структуры, тогда он может вывести, что каждый индекс этого массива равен 0 (поскольку что-то еще есть undefined). Если компилятор этого не знает, то он может вывести, что указатель массива не может указывать на структуру, а изменение элементов массива не может изменить элементы структуры и наоборот.

Вы видите, как это пойдет не так?