Поскольку некоторые редкие реализации используют разные представления для разных типов указателей, Стандарт не требует, чтобы реализации позволяли им взаимозаменяемо манипулировать ими. Вместо этого он рассматривает поддержку таких манипуляций как «популярное расширение», для которого поддержка является проблемой «качества реализации» за пределами его юрисдикции. Практически любой компилятор для платформы с удаленным распространением будет настраиваться для поддержки конструкции, и хотя авторы стандарта хотели дать программистам «шансы на победу» [их слова] для написания переносимого кода, они явно заявили, что сделали не sh, чтобы "унизить" программы, которые не были на 100% переносимыми.
Обратите внимание, однако, что некоторые оптимизаторы не могут обрабатывать такие конструкции, за исключением полного отключения анализа псевдонимов на основе типов, и любая программа, использующая такие конструкции, должна будет документировать такое требование. С другой стороны, если не нужно ориентироваться на непонятные архитектуры, часто лучше использовать конструкции и документировать их использование часто лучше, чем перепрыгивать через обручи для размещения оптимизаторов низкого качества.
Обратите внимание, что даже хорошо качественные компиляторы могут быть сбиты с толку некоторыми достаточно хитрыми шаблонами использования, включающими приведение указателей. Авторы Стандарта не хотели запрещать реализациям выполнять полезную оптимизацию только потому, что некоторые хитрые и надуманные шаблоны использования могли привести к неправильному поведению, но они ожидали, что реализации смогут распознавать шаблоны, которые их пользователи фактически используют. Например, с учетом:
float f;
int *ip; float *fp;
int *ipp = (int**)(&fp);
...
void test(void)
{
fp = &f;
f = 1.0;
**ip+=1;
return f;
}
компилятор не сможет реально c определить, что запись в **ip
может реально повлиять на объект типа float
. Однако, если адрес fp
был сохранен в ip
между записью в f
и последующим чтением из нее, оптимизирующие компиляторы в эпоху, когда был написан стандарт, распознали бы, что преобразование T*
в U*
следует рассматривать как потенциальный удар памяти для любого объекта типа T*
, к которому можно получить доступ через U*
. Я подозреваю, что ваши шаблоны использования соответствуют последнему шаблону гораздо сильнее, чем первый.
*ipp = someFloat;