-Нет в принтф в С - PullRequest
       14

-Нет в принтф в С

2 голосов
/ 12 марта 2011

В настоящее время у меня возникают проблемы с Raytracer "Engine" в некоторых вычислениях.

  info->eyex = -1000.0;
  info->eyey = 0.0;
  printf("%f et %f et %f et %f et %f\n", info->eyex, info->vx, info->eyey, info->vy, info->vz);

Например, в этом фрагменте кода значения кажутся хорошими, но info->eyex дает мне -nanошибка.

Это странно, потому что я сбросил значение раньше.

Ответы [ 2 ]

3 голосов
/ 02 июля 2011

Мой психический смысл подсказывает мне, что eyex объявлено как int, а не как double, как должно быть. Когда вы назначаете ему -1000.0, оно усекается до целого числа -1000 (ваш компилятор должен выдать вам предупреждение здесь), которое представляется в двоичном виде как 0xFFFFFC18 с использованием двоичной нотации дополнения. Аналогично, при условии, что eye также является целым числом, его значение 0 представляется в двоичном виде как 0x00000000.

Когда вы передаете eyex, eyey и другие параметры в printf, они помещаются в стек, чтобы они лежали в памяти с увеличивающимися адресами. Поэтому непосредственно перед инструкцией call для вызова подпрограммы кадр стека выглядит примерно так:

<top of stack>
0xFFFFFC18   ; eyex
(4-8 bytes)  ; vx
0x00000000   ; eyey
(4-8 bytes)  ; vy
(4-8 bytes)  ; vz

Когда printf видит спецификатор формата %f, который говорит: «возьмите 8 байтов из стека, интерпретируйте их как значение double и распечатайте это значение double». Таким образом, он видит значение 0xFFFFFC18xxxxxxxx, где xxxxxxxxx - это значение info->vx. Независимо от этого значения, это IEEE 754 представление NaN, или "не число". У него установлен бит знака, поэтому некоторые реализации могут интерпретировать это как «отрицательный NaN», хотя это имеет ту же семантику, что и обычный NaN.

Ваш компилятор также должен предупредить вас, что вы передаете неправильные типы аргументов в printf - он ожидает double, но вы его не передаете. GCC включает эти предупреждения с помощью -Wall, что я настоятельно рекомендую включить.

Итак, решение состоит в том, чтобы объявить eyex типа double (и, предположительно, другие переменные также будут double, если они еще не были). В качестве альтернативы, если вы не контролируете определение eyex и др. (Скажем, потому что они являются частью структуры сторонней библиотеки), то вместо этого вам следует распечатать их с %d модификатор для печати их в виде целых чисел, а не с %f, и вы также должны назначить им целочисленные значения, такие как -1000 и 0, а не значения с плавающей запятой, такие как -1000.0 и 0.0.

1 голос
/ 01 июля 2011

Просто чтобы подтвердить это. Я точно не знаю, что вызывает такое поведение. printf оптимизируется во время компиляции, а строка формата анализируется. Вероятно, это (неправильно) предполагает что-то о вашей переменной. Несмотря на то, что% f должен работать для двойников и чисел с плавающей запятой, кажется, что это не всегда (по крайней мере, для gcc 4.4.5, который я использую)

Попробуйте присвоить значение другой переменной, а затем передать его в printf. Хотя уродливо, это решило проблему для меня.

...