Представление ловушки

  1. Что такое "представление ловушек" в C (некоторые примеры могут помочь)? Это относится к C++?

  2. Учитывая этот код...

    float f=3.5;
    int *pi = (int*)&f;
    

    ... и предполагая, что sizeof(int) == sizeof(float), имеют ли f и *pi одинаковое двоичное представление/шаблон?

Ответы

Ответ 1

  • Представление ловушки - это общий термин, используемый C99 (IIRC не C89) для описания битовых шаблонов, которые вписываются в пространство, занимаемое типом, но запускают поведение undefined, если оно используется как значение этот тип. Это определение содержится в разделе 6.2.6.1p5 (с щупальцами во всех 6.2.6), и я не буду приводить его здесь, потому что он длинный и запутанный. Тип, для которого существуют такие битовые шаблоны, называется "иметь" ловушечные представления. Для наличия каких-либо ловушечных представлений не требуется тип, но единственным типом, который стандартные гарантии не будут иметь ловушечных представлений, является unsigned char (6.2.6.1p5, 6.2.6.2p1).

    Стандарт дает два гипотетических примера ловушечных представлений, ни один из которых не соответствует чему-либо, что какой-либо реальный процессор выполнял в течение многих лет, поэтому я не собираюсь смущать вас с ними. Хорошим примером представления ловушки (также единственное, что квалифицируется как представление ловушки аппаратного уровня на любом CPU, с которым вы, вероятно, столкнетесь) является сигнальным NaN в типе с плавающей точкой. C99 Приложение F (раздел 2.1) явно оставляет поведение сигнальных NaNs undefined, хотя IEC 60559 подробно описывает их поведение.

    Стоит отметить, что, хотя типам указателей разрешено иметь ловушечные представления, нулевые указатели не являются ловушками. Нулевые указатели вызывают поведение undefined, если они разыменованы или смещены; другие операции над ними (что наиболее важно, сравнения и копии) четко определены. Представления Trap вызывают поведение undefined, если вы просто читаете их, используя тип, который имеет представление ловушки. (Неверные, но не нулевые указатели являются или должны рассматриваться как ловушечные представления, являются предметом обсуждения. ЦП не относится к ним таким образом, но компилятор может.)

  • Код, который вы показываете, имеет поведение undefined, но это из-за правил сглаживания указателей, а не из-за ловушек. Вот как преобразовать a float в int с тем же представлением (предполагая, как вы говорите, sizeof(float) == sizeof(int))

    int extract_int(float f)
    {
        union { int i; float f; } u;
        u.f = f;
        return u.i;
    }
    

    Этот код имеет неуказанное поведение (не undefined) в C99, что в основном означает, что стандарт не определяет, какое целочисленное значение создается, но вы получаете некоторое действительное целочисленное значение, это не представление ловушки, а компилятор не разрешается оптимизировать, исходя из предположения, что вы этого не сделали. (Раздел 6.2.6.1, параграф 7. Моя копия C99 может включать технические корректуры - мое воспоминание состоит в том, что это было undefined в оригинальной публикации, но было изменено на неуказанное в TC.)

Ответ 2

Undefined для псевдонима float с указателем на объект.

Ответ 3

В общем, любое значение с плавающей запятой без прерывания IEEE-754 может быть представлено как целое число на некоторых платформах без каких-либо проблем. Однако существуют значения с плавающей запятой, которые могут привести к неожиданному поведению, если вы предполагаете, что все значения с плавающей запятой имеют уникальное целочисленное представление, и вам случается заставить FPU загрузить это значение.

(Пример взят из http://www.dmh2000.com/cpp/dswap.shtml)

Например, при работе с данными FP вам необходимо выполнить маршалинг между процессорами с различным порядком байтов, вы можете подумать о следующем:

double swap(double)

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

Другими словами, есть некоторые значения FP, которые не имеют соответствующего битового представления, если вы не конвертируете правильно (под правильным я имею в виду union, memcpy через char * или другой стандартный механизм).