Разыменование адреса приведенной к указателю переменной - PullRequest
2 голосов
/ 10 мая 2019

Я нашел этот код в большом проекте, и это действительно заставило меня задуматься.

float sift_handler(int rs2, int rs4, int rs5);
int result1;


float temp = sift_hander(rs2, rs4, rs5);
result1 = *(int*)&temp;

Как я понимаю, адрес с плавающей точкой temp приводится к указателю int и затем разыменовывается.Когда я компилирую этот код, я получаю предупреждение

warning: dereferencing type-punned pointer will break strict-aliasing rules

Каковы реальные преимущества этого против result1 = temp?Также лучше использовать round(), чем просто кастинг?

Ответы [ 3 ]

2 голосов
/ 10 мая 2019

Раньше это был старый трюк для доступа к представлению с плавающей точкой. Это означает, что он не является приведением и (если не перехвачен UB) даст другой результат, кроме 0 в обычной реализации.

По крайней мере, начиная с C99 и C ++ 11 (не уверены в предыдущих версиях), выполнение этого вызывает Undefined Behavior, поскольку он нарушает правило строгого псевдонима. Это правило было изобретено, чтобы помочь компилятору в их оптимизации, заявив, что переменная может быть доступна только через ее собственный тип или через символьный тип. Таким образом, когда компилятор сохранил число с плавающей точкой в ​​регистре, он может предположить, что это число не будет изменено никаким целочисленным изменением (очень упрощенное объяснение).

Но так как он интенсивно использовался в старых программах, большинство компиляторов (даже последние) имеют возможность игнорировать правило строгого псевдонима.

Здесь ваш компилятор просто предупреждает вас, что этот код нарушает правило строгого алиасинга и может вызывать UB в некоторых реализациях.

TL / DR: использование приведенного указателя для доступа к другому типу является попыткой переинтерпретировать базовое представление и является UB как на C, так и на C ++. Это определенно не то же самое, что и актеры.

2 голосов
/ 10 мая 2019

Каковы реальные преимущества этого по сравнению с result1 = temp?

Это совершенно разные операции.result1 = temp преобразует значение из числа с плавающей точкой в ​​целое число.Если temp равно 1.0f, то result1 будет 1.Если стиль округления по умолчанию (который является просто усечением) не является удовлетворительным, вы можете использовать round() перед присвоением целому числу.

*(int*)&temp с другой стороны переосмысливает биты float переменная и сохраняет эти биты в целочисленную переменную.1.0f может привести к огромному целочисленному значению.Это называется type punning .

Как говорит компилятор, выполнение этой разыменования с указателем недопустимого типа является строгим нарушением алиасинга .Правильный способ сделать этот тип наказания будет:

memcpy(&result, &temp, sizeof temp);
0 голосов
/ 10 мая 2019

Каковы реальные преимущества этого по сравнению с result1 = temp

Он делает что-то совершенно другое, и не переводит число с плавающей точкой в ​​целое число. Так что просто не используйте наложение указателя, пока вы не хорошо поймете указатели, типы данных, их представление в конкретной реализации и т. Д. И т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...