Приведение к (int *) из (&num), когда num является числом с плавающей запятой в C

Почему выводится следующий код: «i is: 1075838976»?

#include <stdio.h>

int main(){
  int i = 2;
  float num = 2.5;

  i = *((int *)& num);
  printf("i is: %d\n", i);
} 

Разве это не эквивалентно:

#include <stdio.h>

int main(){
  int i = 2;
  float num = 2.5;

  i = num;
  printf("i is: %d\n", i);
} 

Какие выходы: «i is 2»? Спасибо.


person rok    schedule 23.07.2013    source источник
comment
Нет, это (очевидно) не эквивалентно. Один переинтерпретирует битовый шаблон (вызывая неопределенное поведение по пути), другой выполняет преобразование значения.   -  person Daniel Fischer    schedule 23.07.2013
comment
Сильно связанный, возможно, даже дубликат: stackoverflow.com/q/3452439/319403   -  person cHao    schedule 23.07.2013


Ответы (3)


Нет, это совсем не равнозначно.

Этот:

i = num;

преобразует значение числа num (то есть 2.5) из float в int. Преобразование усекает значение до 2.

Этот:

i = *((int *)& num);

берет указатель на объект float num, преобразует его в int* и разыменовывает результирующий указатель.

Если вам «повезло», это берет биты, составляющие представление num, притворяется, что они являются представлением int, и дает вам эти результаты.

Если вам не «повезло», то int и float могут быть разных размеров, объект float может быть неправильно выровнен, чтобы его можно было рассматривать как объект int, или результатом может быть даже «представление-ловушка» (хотя последнее редкий).

(Я взял слово «повезло» в кавычки, потому что на самом деле лучшее, что может сделать этот код, — это взорваться у вас перед носом, что немедленно даст вам понять, что вы делаете что-то сомнительное. Поведение такое: < em>undefined, что означает ошибку, но реализация не обязана предупреждать вас об этом ни во время компиляции, ни во время выполнения.)

Конкретное значение, которое вы получаете, 1075838976, может быть представлено в шестнадцатеричном формате как 0x40200000. Если вы посмотрите, как значения float представлены в вашей системе, вы, вероятно, сможете понять, как эта битовая комбинация (0100 0000 0010 0000 0000 0000 0000 0000) составляет значения знака, мантиссы и экспоненты, которые представляют значение 2.5.

person Keith Thompson    schedule 23.07.2013

В C "приведение" как бы "перегружено" и делает две совершенно разные вещи:

-- Вызывает создание кода для преобразования "скалярного" значения, скажем, между int и float.

-- Привести указатель к другому типу. На самом деле это не генерирует никакого кода и ничего не конвертирует.

((int *)& num) приводит указатель с float* на int* и не выполняет никакого преобразования данных.

person Hot Licks    schedule 23.07.2013

Вы говорите машине интерпретировать двоичное число явно как целое число, не проходя приведение типов.

person Daniel A. White    schedule 23.07.2013