Делает ли использование структуры struct C небезопасным? - PullRequest
5 голосов
/ 12 января 2012

Предположим, у меня есть структура, будь то объединение или нет:

    typedef struct {
        union {
            struct { float x, y, z; } xyz;
            struct { float r, g, b; } rgb;
            float xyz[3];
        } notAnonymous;
    } Vector3;

Я слышал, что некоторые компиляторы автоматически дополняют структуры для повышения производительности путем создания выровненных по словам границ.

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

inline Vector3 v3Make(float x, float y, float z) { Vector3 v = {x,y,z}; return v; }
float xyzs[6];
*(Vector3*)&xyzs[3] = v3Make(4.0f,5.0f,6.0f);
*(Vector3*)&xyzs[0] = v3Make(1.0f,2.0f,3.0f);

Правильно?

Ответы [ 4 ]

3 голосов
/ 12 января 2012

Это правда, что компилятор может выстроить нашу структуру так, как ему захочется.Вы можете использовать #pragma pack или __attribute__((packed)), чтобы избежать заполнения в большинстве компиляторов.На практике у вас есть три 32-битных поля, так что, вероятно, это не будет проблемой.Вы можете проверить, используя sizeof вашего типа структуры или переменную этого типа, и посмотрев, что получится.

Что означает Проблема в том, что вы пытаетесь присвоить *От 1008 * до float в последних двух строках.Это не будет разрешено.Вы можете взломать то, что вы пытаетесь сделать:

*(Vector3 *)&xyzs[3] = v3Make(4.0f, 5.0f, 6.0f);

Но это довольно уродливо, не говоря уже о том, чтобы запутать.Было бы намного лучше изменить xyzs на массив Vector3, а не просто float.

2 голосов
/ 12 января 2012

См. Ответы на вопросы в отчете о дефектах C # 074

http://www.open -std.org / ОТК1 / SC22 / WG14 / документы / RR / dr_074.html

0 голосов
/ 12 января 2012

В соответствии со стандартом C это, по крайней мере, определяется реализацией (зависит от проблем заполнения) и, возможно, не определяет поведение (из-за правил наложения имен?), Но на всех реальных компиляторах это будет работать так, как ожидается. Выравнивание типа никогда не может быть больше его размера (оно всегда делит размер типа равномерно), и только патологически плохой компилятор вставит дополнительное заполнение в структуры, превышающие то, что необходимо для дополнения каждого члена до правильного выравнивания для его типа.

С учетом сказанного, в моей книге, по крайней мере, , этот вид взлома является безвозмездным вызовом неопределенного поведения ради синтаксического уксуса и неприемлем. Если есть шанс получить доступ к данным в стиле массива, просто всегда используйте форму массива. Гораздо менее запутанно помнить, что векторные компоненты всегда v[0], v[1] и v[2], чем помнить, что v[1] и rgb.g могут ссылаться на один и тот же объект в памяти ...

0 голосов
/ 12 января 2012

Это небезопасно, компилятор / компоновщик заботится обо всех смещениях.

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

...