Printf of Double или int - PullRequest
       43

Printf of Double или int

0 голосов
/ 12 февраля 2019

Привет всем,

      int main()
{
  int a = 2;
  double b=2;
  printf( "with the d   a = %d \n", a); // print 2
  printf( "with the d   a = %d \n", b); // **print 0  <== My interrogation?**
  printf( "with the f   a = %f", b); // print 2.000000 
  return 0;
}

Я знаю, что, поскольку мы объявляем b как двойное число, мы должны использовать% f в функции printf.Мой вопрос: глубоко в памяти, почему мы печатаем 0 , так как мы помещаем в b int (даже если программа уже зарезервировала память для двойного) ??

Спасибовы

Ответы [ 3 ]

0 голосов
/ 12 февраля 2019

Двоичное представление 2 в виде двойного IEEE 754 равно 0x4000000000000000, передавая double в printf, который ожидает int, предположительно вызывает приведение к целому числу и просматривает только нижние 4 байта, которыевсе 0, поэтому печатается 0.

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

0 голосов
/ 12 февраля 2019

Это неопределенное поведение (UB), поскольку существует несоответствие между строкой формата и аргументом.Сказав это, и предположив, что компилятор не выполняет некоторые нетривиальные преобразования, тогда UB имеет некоторое типичное поведение в этом случае.

Чтобы увидеть, что происходит, вы должны проверить соглашение о вызовах в системе.Скорее всего, программа работает на 64-битной архитектуре x86, которая передает аргументы в соответствии с соглашениями о вызовах X86 .В окнах первое значение с плавающей запятой передается другим регистром (XMM0), чем целочисленный аргумент (один из RCX, RDX, R8, R9).Это означает, что для:

printf( "with the d   a = %d \n", b); 

double b передается в одно место, а "%d" читает из другого.Также обратите внимание, что соответствующие целые числа считаются энергозависимыми и могут быть сброшены при более раннем вызове printf.Это означает, что int (a = 2), переданный предыдущему printf через регистр, уничтожается тем же printf.По сути, «% d» заставляет printf прочитать значение барахла, оставшееся от внутренней реализации printf.

В результате в Linux и на Mac с помощью clang и gcc я получаю случайное значение барахла вместо нуля.Я предполагаю, что исходный вопрос относится к Visual Studio в Windows, которая может установить целое число в ноль в режиме отладки (или что-то подобное).

Обратите внимание, что нет гарантии с неопределенным поведением.Компилятор может сделать что-нибудь, включая удаление ошибочной строки или что-то совершенно неожиданное.Анализ этого ответа является правильным для данного компилятора, системы и уровня оптимизации.Это наблюдалось в сгенерированной сборке, но любое незначительное изменение (даже в другой функции в коде) может привести к совершенно другому поведению.Никогда не полагайтесь на неопределенное поведение.

0 голосов
/ 12 февраля 2019

У вас неопределенное поведение.

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

Вероятно, происходит то, что double загружается в регистры с плавающей запятой, в то время как printf ищет в стеке значение int.

В наши дни любой порядочный компилятор должен предупреждать вас.когда ваша строка формата не соответствует вашим типам параметров.Всегда читайте эти предупреждения!

...