Подтвердить что ты не робот

Строгое сглаживание в C

Вопрос о типе punning: почему этот код нарушает строгие правила псевдонимов:

int main()
{
    int a = 1;
    short j;

    printf("%i\n", j = *((short*)&a));
    return 0;
}

и это не так:

int main()
{
    int a = 1;
    short j;
    int *p; 

    p=&a;
    printf("%i\n", j = *((short*)p));
    return 0;
}

Создайте gcc -fstrict-aliasing.

Спасибо!

4b9b3361

Ответ 1

Они оба нарушают правило строгое правило aliasing, я собираюсь процитировать мой ответ здесь, в котором говорится (акцент мой идет вперед):

нарушает строгие правила псевдонимов, которые делают незаконным доступ к объекту с помощью указателя другого типа, хотя возможен доступ через char *. Компилятору разрешено предположить, что указатели разных типов не указывают на одну и ту же память и соответственно оптимизируют.

gcc немного подробнее в документации -Wstrict-aliasing=n здесь, в которой говорится:

Эта опция активна только при активном сглаживании сглаживания. Он предупреждает о коде, который может нарушить строгие правила псевдонимов, которые компилятор использует для оптимизации. Более высокие уровни соответствуют более высокой точности (меньше ложных срабатываний). Более высокие уровни также соответствуют большему количеству усилий, подобно тому, как работает -O. -Wstrict-aliasing эквивалентно -Wstrict-aliasing = 3.

и описывает каждый уровень следующим образом:

  • Уровень 1: Самый агрессивный, быстрый, наименее точный. Возможно, полезно, когда более высокие уровни не предупреждают, но -fstrict-aliasing все еще прерывает код, так как у него очень мало ложных негативов. Однако у него много ложных позитивы. Предупреждает обо всех преобразованиях указателя между возможными несовместимые типы, даже если они не были разыменованы. Работает в передней части только.

  • Уровень 2: Агрессивный, быстрый, не слишком точный. Может все еще иметь много ложных (хотя и не так много, как уровень 1), и несколько ложных негативов (но, возможно, больше уровня 1). В отличие от уровня 1, он предупреждает только адрес берется. Предупреждает о неполных типах. Забегает вперед end.

  • Уровень 3 (по умолчанию для -Wlict-aliasing): должно быть очень мало false положительных и мало ложных негативов. Немного медленнее уровней 1 или 2 когда оптимизация включена. Принимает во внимание общий каламбур + разыменование шаблон в интерфейсе: *(int*)&some_float. Если оптимизация включен, он также работает в задней части, где он имеет дело с несколькими с использованием чувствительных к потоку точек - к информации. Только предупреждает когда преобразованный указатель разыменован. Не предупреждает о неполные типы.

Таким образом, не гарантируется улавливание всех экземпляров, а разные уровни имеют разную степень точности.

Обычно эффект, который вы ищете, может быть выполнен с использованием типа punning через объединение, которое я упоминаю в моем связанном ответе выше, и gcc явно поддерживает.