Меня интересует выходное значение формата printf языка c - PullRequest
0 голосов
/ 09 апреля 2020

У меня есть вопрос при изучении C языка.

printf("%d, %f \n", 120, 125.12);

Выходное значение в этом коде:

120, 125.120000

Вот и все. И

printf("%d, %f \n", 120.1, 125.12);

Выходное значение этого кода:

1717986918, 0.000000

Вот и все.

Конечно, я понимаю, что выходное значение% d впереди из нас было странное значение, потому что я поместил ошибку в символ целочисленного формата. Но я не знаю, почему% f после этого составляет 0,000000. Влияет ли персонаж на спине на значение предыдущего символа?

Я спрашиваю, потому что мне любопытно, потому что он продолжает появляться, даже если я выставляю другую цену.

Ответы [ 3 ]

2 голосов
/ 09 апреля 2020

почему% f после этого равно 0,000000.

Согласно стандарту C, поскольку %d ожидает int, а вы передали double, происходит неопределенное поведение и все позволено.

В любом случае: я использовал http://www.binaryconvert.com/convert_double.html для преобразования двойных чисел в биты:

120.1  === 0x405E066666666666 
125.12 === 0x405F47AE147AE148

Я полагаю, что ваша платформа x86-i sh, прямым порядком, с моделью данных ILP32.

Спецификатор формата %d printf предназначен для int, а sizeof(int) - 4 байта или 32 бита в LP64. Поскольку архитектура имеет прямой порядок байтов и стек тоже, первые 4 байта из стека равны 0x66666666, и распечатывается ее десятичное значение, равное 1717986918.

. В стеке остаются три 32 -битные слова с прямым порядком байтов, давайте разделим их 0x405E0666 0x147AE148 0x405F47AE.

Спецификатор формата %f printf предназначен для double и sizeof(double) на вашей платформе 8 или 64 бита. Мы уже прочитали 4 байта из стека, и теперь мы читаем 8 байтов. Вспоминая о порядке байтов, мы читаем 0x147AE148405E0666, который преобразуется в двойной. Я снова использовал этот сайт и преобразовал гекс в двойной, в результате чего 5.11013578783948654276686949883E-210. E-210 - это очень и очень небольшое число. Поскольку %f по умолчанию печатает с точностью до 6 цифр, начальные 7 цифр числа равны 0, поэтому печатаются только нули. Если вы используете спецификатор формата %g printf, то номер будет напечатан как 5.11014e-210.

2 голосов
/ 09 апреля 2020

printf - это функция variadi c, то есть ее типы аргументов и число переменных Как таковые, они должны быть извлечены в соответствии с их типом. Извлечение данного аргумента зависит от правильного извлечения аргументов, предшествующих ему. Разные типы аргументов имеют разные размеры, выравнивания и т. Д. c.

Если вы используете неверный спецификатор формата для аргумента printf, то он выбрасывает printf из syn c. Обычно аргументы после того, который был извлечен неправильно, не будут извлечены правильно.

В вашем примере, вероятно, он извлек только часть первого переданного аргумента double, так как ожидал int аргумент. После этого он был не синхронизирован c и неправильно извлек второй аргумент double. Это спекулятивно, хотя и варьируется от одной архитектуры к другой. Поведение не определено.

0 голосов
/ 09 апреля 2020

Это может быть связано с тем, что функция printf не является типобезопасной, то есть нет связи между спецификаторами в строке формата и переданными аргументами.

Функция преобразует все целые числа аргументы int (4 байта) и все плавающие до double (8 байтов). Поскольку типы угадываются из строки формата, происходит смещение данных. Вполне вероятно, что 0.000000 появляется, потому что загруженное соответствует нулю с плавающей точкой (смещенная экспонента = 0).

Попробуйте с 1.0, 1.e34.

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