Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > преобразование указателей


Автор: wladF 22.5.2013, 18:48
Привет.

Прочитал множество тем и обсуждений проблемы алиасинга памяти(указателей). Но так и никакого вывода в итоге и не сделал. Есть несколько конкретных вопросов.

1) Безопасно ли всё-таки использовать в C и C++ различные типы указателей(кроме char*), указывающих на один и тот же объект, если гарантируется, что проблем с выравниванием не будет?

2) Безопасно ли использовать в C и C++ "неактивные" члены union(после изменения другого члена)?

3) Strict aliasing rule(или другое подобное название) введена как фича GCC или это требование стандарта C и C++?

4) Если хотя бы одно из этих правил нарушено, то как вообще работают миллионы строк кода с этими "дефектами"?

Автор: baldina 22.5.2013, 20:28
1. указатели могут быть любые, проблема не в указателях а в разыменовании. при разыменовании все зависит от того, что конкретно находится по адресу.
2. что значит "использовать"? если это принципиально разные типы, чтение бессмысленно, но запись безопасна. если union сделан для удобства манипулирования низкоуровневыми структурами (для этого его вобщем-то и ввели), то "использование" и является целью применения union.
3. C99. в С++ нет, но компиляторы поддерживают
4. Бог милостив

http://habrahabr.ru/post/114117/

Автор: mabrarov 22.5.2013, 21:17
Цитата(wladF @ 22.5.2013,  18:48)
2) Безопасно ли использовать в C и C++ "неактивные" члены union(после изменения другого члена)?

Насколько я знаю, это UB. Т.е. записать в один нестатичный член union, и прочитать то, что записали, через другой нестатичный член - это UB (за исключением тех случаев, что перечислены в цитате стандарта ниже).

Цитата(wladF @ 22.5.2013,  18:48)
3) Strict aliasing rule(или другое подобное название) введена как фича GCC или это требование стандарта C и C++?

Среди первых результатов поиска, что выдает Google: http://stackoverflow.com/questions/2771023/c99-strict-aliasing-rules-in-c-gcc.
Т.е. strict aliasing есть уже в C++98 (параграф 3.10, пункт 15).
В C++11 (взял из draft, параграф 3.10, пункт 10):
Цитата
If a program attempts to access the stored value of an object through a glvalue of other than one of the
following types the behavior is undefined:
— the dynamic type of the object,
— a cv-qualified version of the dynamic type of the object,
— a type similar (as defined in 4.4) to the dynamic type of the object,
— a type that is the signed or unsigned type corresponding to the dynamic type of the object,
— a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type
of the object,
— an aggregate or union type that includes one of the aforementioned types among its elements or nonstatic
data members (including, recursively, an element or non-static data member of a subaggregate
or contained union),
— a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
— a char or unsigned char type.

Цитата(wladF @ 22.5.2013,  18:48)
4) Если хотя бы одно из этих правил нарушено, то как вообще работают миллионы строк кода с этими "дефектами"?

Например, в Visual C++ strict aliasing, как мне показалось за все время его использования, вообще не работает (похоже его там попросту нет). 
В остальных случаях: 
Цитата(baldina)
Бог милостив

https://blog.qt.digia.com/blog/2011/06/10/type-punning-and-strict-aliasing/, например, в Qt была проблема со strict aliasing.

Автор: volatile 23.5.2013, 00:47
Цитата(mabrarov @  22.5.2013,  21:17 Найти цитируемый пост)
в Visual C++ strict aliasing, как мне показалось за все время его использования, вообще не работает 

strict aliasing -это всего лишь оптимизация. 
Точнее некоторое послабление компилятору, в надежде что он сгенерит более оптимальный код,
и как любое послабление - потенциальный источник багов.

Автор: mabrarov 23.5.2013, 02:10
Цитата(volatile @ 23.5.2013,  00:47)
strict aliasing -это всего лишь оптимизация. 
Точнее некоторое послабление компилятору, в надежде что он сгенерит более оптимальный код,
и как любое послабление - потенциальный источник багов.

В целом согласен (хотя необязательность соблюдения strict aliasing rules компилятором не является достаточным условием, чтобы не учитывать это правило в исходном коде на C++), но (!) strict aliasing очень важное условие для "качественной" компиляции в плане использования регистровой памяти (которой становится все больше с каждым новым поколением процессоров/архитектур).
Берем Google: http://www.google.com/search?hl=ru&q=Why+fortran+is+faster+than+C%2B%2B и http://stackoverflow.com/questions/146159/is-fortran-faster-than-c (ну или http://stackoverflow.com/questions/610396/languages-faster-than-c):
Цитата
The languages have similar feature-set. The performance difference comes from the fact that fortran says aliasing is not allowed. Any code that has aliasing is not valid fortran but it is up to the programmer and not the compiler to detect these errors. Thus fortran compilers ignore possible aliasing of memory pointers and allows them to generate more efficient code.

Автор: Dem_max 23.5.2013, 09:21
Цитата

Берем Google: Why fortran is faster than C++ и находим (ну или вот это):

Fortran был всегда быстрее, я не говорю уж о С++, а если сравнивать с Си. Даже на простом коде но его выполнит быстрее.

Автор: wladF 23.5.2013, 10:45
Цитата(baldina @ 22.5.2013,  20:28)
1. указатели могут быть любые, проблема не в указателях а в разыменовании. при разыменовании все зависит от того, что конкретно находится по адресу.
2. что значит "использовать"? если это принципиально разные типы, чтение бессмысленно, но запись безопасна. если union сделан для удобства манипулирования низкоуровневыми структурами (для этого его вобщем-то и ввели), то "использование" и является целью применения union.
3. C99. в С++ нет, но компиляторы поддерживают
4. Бог милостив

http://habrahabr.ru/post/114117/

1. Уточню. Речь шла конечно же о разыменовании таких указателей на POD-типы. 

2. Чтение не бессмысленно. Пример:
Код

Union U {
    int a;
    float b;
} u;
..
u.a = //.. используем целочисленные операции 
return u.b;


По ссылке читал давно. Выводов вообще не понял.

Автор: mabrarov 23.5.2013, 12:38
Цитата(wladF @ 23.5.2013,  10:45)
1. Уточню. Речь шла конечно же о разыменовании таких указателей на POD-типы. 

Разве это что-то меняет (за исключением особых случаев с char/unsinged char)? 

Цитата(wladF @ 23.5.2013,  10:45)
2. Чтение не бессмысленно. Пример:
Код

Union U {
    int a;
    float b;
} u;
..
u.a = //.. используем целочисленные операции 
return u.b;

Насколько я понял, http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html:
Цитата
Casting through a union (1)
...
Strictly speaking, reading a member of a union different from the one written to is undefined in ANSI/ISO C99 except in the special case of type-punning to a char*, similar to the example below: Casting to char*. However, it is an extremely common idiom and is well-supported by all major compilers. As a practical matter, reading and writing to any member of a union, in any order, is acceptable practice.

А вот "Casting through a union (2)" в "Understanding Strict Aliasing" стандартом не запрещен (т.е. разрешен), но вызывает ложные предупреждения со стороны GCC.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)