Когда строго сглаживание включено, компилятор позволил предположить, что два указателя различного типа (char*
против cmt_t*
в данном случае) не будет указывать на ту же ячейку памяти. Это позволяет использовать больший диапазон оптимизаций, которые в противном случае вы бы не хотели применять, если они действительно указывают на одно и то же место в памяти. Различные примеры/ужасные истории можно найти в этом question.
Именно поэтому, при строгом сглаживании, вы должны быть осторожны, как вы набираете караоке. Я считаю, что стандарт не допускает каких-либо действий, связанных с типом, что-то никогда (не цитируйте меня на этом), но большинство компиляторов имеют исключения для профсоюзов (мой google-fu не работает, чтобы открыть соответствующие страницы руководства) :
union float_to_int {
double d;
uint64_t i;
};
union float_to_int ftoi;
ftoi.d = 1.0;
... = ftoi.i;
к сожалению, это не совсем работа для вашей ситуации, как вы бы memcpy
содержимого массива в союз, который является менее идеальным. Более простой подход состоял бы в том, чтобы просто отключить строгое сглаживание с помощью переключателя -fno-strict-aliasing
. Это обеспечит правильность вашего кода, и вряд ли оно окажет существенное влияние на производительность (важно измерять эффективность работы).
Что касается того, почему предупреждение не появляется, когда линия разбита, я не знаю. Скорее всего, изменения в исходном коде позволяют запутать статический аналитический анализ компилятора, достаточный для того, чтобы он не видел тип-punning. Обратите внимание, что статический анализ, ответственный за обнаружение типа punning, не связан и не говорит о различных проходах оптимизации, которые предполагают строгое сглаживание. Вы можете придумать какой-либо статический анализ, сделанный компиляторами (если не указано иное) как наиболее подходящий тип вещей. Другими словами, отсутствие предупреждения не означает, что ошибок нет, а это означает, что простое разрывание линии не волшебным образом делает ваш тип караоке безопасным.