Я могу рассматривать структуру как массив?

У меня есть структура для содержания 4D вектор

struct {
    float x;
    float y;
    float z;
    float w;
} vector4f

И я пользуюсь библиотекой, которая имеет некоторые функции, которые воздействуют на векторы, но берут указатели плавающие в качестве их аргументов.

Действительно ли законно назвать что-то как doSomethingWithVectors( (float *) &myVector)?

7
задан spencewah 27 December 2009 в 22:44
поделиться

8 ответов

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

.
10
ответ дан 6 December 2019 в 06:24
поделиться

Если бы у меня была такая ситуация, я бы так и сделал: Псевдонимы переменных членов C++?

В вашем случае это выглядело бы так:

struct {
        float& x() { return values[0]; }
        float& y() { return values[1]; }
        float& z() { return values[2]; }
        float& w() { return values[3]; }

        float  operator [] (unsigned i) const { return this->values_[i]; }
        float& operator [] (unsigned i)       { return this->values_[i]; }
        operator float*() const { return this->values_; }

private:
        float[4] values_;
} vector4f;

Однако, это не решает вопроса об обращении со структурой как со массивом, если это именно то, о чем вы хотели узнать.

0
ответ дан 6 December 2019 в 06:24
поделиться

Да, это будет работать на любом компиляторе, который следует стандарту C99. Вероятно, это также будет работать и с компиляторами, использующими более ранние, менее понятные стандарты.

Вот почему:

6.2.5.20 определяет массивы как "последовательно выделенные" элементы, в то время как структуры являются "последовательно выделенными" членами, и пока все члены структуры одного и того же типа, это действительно одно и то же.

6. 5.2.3 guarentees, что если типы используются в видимом в настоящее время объединении, то можно прозрачно использовать вещи, расположенные в одном и том же порядке.

6.5 ясно показывает, что "эффективный тип" для любого доступа к элементу массива или полю структуры является "float", так что любые два доступа могут иметь псевдонимы. Доступ к структуре в целом на самом деле является доступом к каждому члену массива по очереди, поэтому применяются одни и те же правила псевдонимов.

Требование "union" является наиболее странным, но поскольку типы, объявленные, когда объединение видимо, должны быть совместимы с типами, определенными одинаково в другой компиляционной единице без объединения, те же самые правила в конечном итоге применяются даже там, где объединение не видимо.

Редактирование

Ключевым моментом здесь является различие между неопределенными вещами и вещами, которые определены в реализации. Для неопределенных вещей компилятор может делать что угодно, и может делать разные вещи при перекомпиляции одного и того же файла исходного текста. Для вещей, определенных реализацией, вы можете не знать точно, что он делает, но он должен делать одно и то же последовательно во всех модулях компиляции. Так что даже там, где спецификация точно не описывает, как что-то должно быть сделано, взаимодействие между различными вещами и тот факт, что вещи должны быть согласованы между модулями компиляции с помощью скомпилируемых объявлений типа, сильно ограничивает то, что компилятор может здесь сделать.

.
-1
ответ дан 6 December 2019 в 06:24
поделиться

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

В языке Си взятие области хранения, занимаемой значением одного типа, и ее переинтерпретация как другого типа почти всегда противозаконна. Из этого правила есть несколько исключений (поэтому я сказал "почти"), например, можно переинтерпретировать любой объект как char-массив, но в целом это явно противозаконно.

Более того, возможные опасности не чисто теоретические, и речь идет не только о возможных различиях в выравнивании массивов и структур. Современные компиляторы могут полагаться (и полагаются) на вышеупомянутое правило языка для выполнения оптимизации алиасинга (читайте, например, о строгой семантике алиасинга в GCC). Короче говоря, компилятору разрешено транслировать код в предположении, что память, занятая структурой , никогда не сможет перекрыть память, занятую массивом float. Это часто приводит к неожиданным результатам, когда люди начинают использовать трюки, как в Вашем сообщении.

.
8
ответ дан 6 December 2019 в 06:24
поделиться

Нет, это не законно. И почти каждый раз, когда вы оказываетесь в гипсе, вы должны заподозрить, что с вашим кодом что-то глубоко не так. Я подозреваю, что кто-то вскоре предложит использовать профсоюз, но это тоже не будет законно.

Конечно, законно или нет, или подход, который вы предлагаете в вашем вопросе, или использование профсоюза, скорее всего, "сработает" - но это не то, о чем вы спрашивали.

.
1
ответ дан 6 December 2019 в 06:24
поделиться

Вау. Есть много ответов, в которых говорится, что это сработает. Это не гарантируется стандартом C. В ответ на комментарий, запрашивающий реальный пример, есть этот отличный пост Криса Торека из comp.lang.c . Окончательная цитата: Урок здесь тот же, что и всегда: "Если вы лжете компилятору, он получит свою месть"

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

.
6
ответ дан 6 December 2019 в 06:24
поделиться

Давайте просто выкинем все аргументы о правильном пути™, чтобы сделать что-нибудь в окне на минуту.

Работает ли это, чтобы трактовать эту структуру как массив? Да. Будет ли это работать во всех случаях, на всех компиляторах и платформах? Нет.

Floats обычно 32-битные, и даже на моей 64-битной машине они выравниваются по границам 32-битных слов.

#include <stdio.h>

struct {
        float x;
        float y;
        float z;
        float w;
} vector4f;

float array4f[4];

int main(int argc, char **argv) {
        printf("Struct: %lu\n", sizeof(vector4f)); // 16
        printf(" Array: %lu\n", sizeof(array4f));  // 16

        return (0);
}
3
ответ дан 6 December 2019 в 06:24
поделиться

Если Вам нужен массив, почему бы Вам не поместить массив внутрь Вашей структуры и не использовать его? Я полагаю, что Вы могли бы добавить указатели, если бы все равно хотели получить доступ к нему таким же образом, используя vector4f.x vector4f.y vector4f.z

struct {
    float vect[4];
    float* x;
    float* y;
    float* z;
    float* w;
} vector4f

Конечно, это сделало бы Вашу структуру больше и сложнее при инициализации

.
1
ответ дан 6 December 2019 в 06:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: