2013-06-01 2 views
-1

У меня есть такой код:Почему int pointer дает мне число с плавающей запятой?

double x = 100.1; 
double y; 
int *p; 

p = (int *) &x; 
y = *p; 

cout << "y value is: " << y << endl; 

Я понимаю, что это неправильно, и мы получаем 4 байта вместо наших 8 байт. Я также знаю, плавающие числа имеют некоторое хитрое представление в памяти (но не знаю, как), но этот сценарий дает мне такой вывод:

y value is: 1.71799e+09 

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

+1

Вы * сделали * получите результат int. Он просто отформатирован с использованием представления, которое подходит только для двойного. Потому что это то, что делает cout, когда вы передаете переменную типа double. И, конечно, имеет случайное значение, где-то между +/- 2 миллиардами. –

+1

Целое число было приблизительно 1717990000 (из-за сложного представления, которое вы отметили). Затем вы преобразовали его в плавающую точку и распечатали. –

+0

GIGO. (Для детей, это древний вычислительный термин, который обозначает Garbage In, Garbage Out) –

ответ

6

По моему указателю есть int, и я также ожидаю результата int. Почему это не так?

Потому что y является двойным, а не внутренним. Теперь, если вы хотите спросить, почему y не имеет целочисленного значения, так как это должно быть результатом преобразования int (которое должно * иметь интегральное значение), чтобы удвоить, посмотрите на вывод следующих :

std::cout << "y value is: " << std::fixed << y << '\n'; 

выход вы должны увидеть:

y value is: 1717986918.000000 

Так, yделает имеет целочисленное значение, вы просто выводил его с помощью научной нотации. И если вам интересно, почему y имеет это конкретное целочисленное значение, это потому, что это значение *p было.

std::cout << "*p is: " << *p << '\n'; 

*p is: 1717986918 

Если вы должны были смотреть на свалку памяти x со значением 100.1, вы бы увидели:

66 66 66 66 66 06 59 40 

И когда вы получить доступ к этому как межд, вы получаете 66 66 66 66, который, преобразуется в десятичное, является 1717986918.


Еще одна вещь, следует отметить, что ни одно из этого не гарантируется C++. На самом деле ваша программа на самом деле не является законной, поскольку вы нарушаете правила псевдонимов при доступе к двойному x с помощью указателя на int.Ваша программа может стать законной и получить те же результаты, но C++ не указывает представление значений с плавающей запятой, поэтому конкретное целочисленное значение может легально отличаться.


Что я должен читать, чтобы понять?

Вот статья, которая играет с представлением поплавков: http://ridiculousfish.com/blog/posts/float.html

C++ не определяет, как представлены поплавки, но в большинстве реализаций C++ используют IEEE-754, так что вы можете также смотреть на что Спецификация. Вот страница wikipedia, чтобы вы начали: https://en.wikipedia.org/wiki/IEEE_floating_point

Чтобы узнать о правилах псевдонимов C++, вы можете найти и прочитать спецификацию. строгое сглаживание описано в §3.10/10, IIRC. Здесь также много вопросов и ответов об использовании псевдонимов на SO.

3

Когда вы

y = *p; 

переменная у принимает INT указывает р, а затем преобразует его в дубль.

Пусть является 4

Doing x = 100; вы положили double значение 100 в х на 8 байт. Затем, когда вы делаете y = *p;, вы использовали бы только 4 из 8 байтов, как значение int, затем конвертируйте это число в double.

Бинарный формат двойной и int разные. Например. 100 как double не представлен таким же образом, как 100 int (не говоря уже о разнице в размерах, например, 8 против 4).

See this link

4

1.71799e+09 является точкой представление с плавающей целочисленной 1,717,99x, ххх.

+0

Хотя это может быть правдой, на самом деле это не отвечает на вопрос. – Devolus

+0

@Devolus: Ответ на вопрос «Я также ожидаю результата int. Почему это не так?» что ** это **. '1.71799e + 09' ** является ** целым числом, представленным как' double'. Он не имеет дробной составляющей. – RichieHindle

+0

А теперь я понимаю, что вы имеете в виду. – Devolus

4

По моему указателю есть int, и я также ожидаю результата int. Почему это не так?

Ваш указатель являетсяint *, и вы являются получение int результата.

Но это не то, что вы показываете. Вы показываете y, который является double.

1.71799e+09 - это двойное представление int, которое вы получили.

3
double x = 100.1; 
double y; 
int *p; 

p = (int *) &x;  
// Set a pointer of type integer to point at a floating point. Better C++ style 
// would be p = reinterpret_cast<int *>(&x); 
// which explains more clearly what you are doing - reinterpreting the pointer as 
// a different type. 

y = *p; 
// *p is an integer. So y is set to the value of *p, which is some crazy 
// integer value formed from the interpretation of a double as integer. 

cout << "y value is: " << y << endl; 

См. Комментарии в коде выше. Вы делаете указательный пункт для данных другого типа, а затем задаетесь вопросом, почему преобразованные двоичные цифры не представляют то, что изначально было представлено ...

(Технически этот код нарушает правила псевдонимов - в основном, вы используете один и тот же кусок памяти для двух разных целей, а компилятор не обязан «делать правильные вещи» в этом случае - Я подозреваю, что он делает что-то от того, что вы можете ожидать в этом конкретном случае - если вы ожидаете, что вы получите целочисленное значение, представленное четырьмя четырьмя байтами двойника, то есть).

Если вы хотите y на самом деле содержат целое представление числа в x, вы хотите:

y = (int)x; 

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

+1

Использование 'reinterpret_cast' не делает код более правильным; это по-прежнему нарушение псевдонимов, и этот конкретный стиль C-стиля, в любом случае, определяется как 'reinterpret_cast'. – bames53

+0

Я сказал, что он объяснит более ясно, что это переинтерпретация указателя - и я думаю, что это так. Если вы считаете, что новичок понимает (int *) так же ясно, тогда не стесняйтесь думать так. –

+0

Моя жалоба заключается в том, что вы сказали: «Правильно C++ будет ...», но это уже не так. – bames53

0

Вы запуск неопределенной behavoir при запуске следующей строки:

p = (int *) &x; 

После того, как вы вызвали undefined behavour, остальная часть вашего вопроса довольно бессмысленна, поскольку рассуждение о неопределенном поведении r не имеет смысла (хотя, глядя на остальную часть вашего вопроса, может случиться так, что этот бит неопределенного поведения не влияет на то, что вы действительно спрашиваете. Я не уверен, хотя.)

+0

Вы бы добавили его в комментарий в этом случае – pinkpanther

+1

Как раз из моего личного любопытства, как отличает int указатель на указатель float неопределенное поведение? Отказ от такого указателя может быть зависимым от реализации, но литье? Какая часть стандарта? – AlexK

Смежные вопросы