О спецификаторе преобразования в C

c format-specifiers

573 просмотра

2 ответа

895 Репутация автора

У меня есть вопрос о спецификаторе преобразования в C.

В 5-м предложении, если я использую %lfили %Lfвместо %f, никакой ошибки не возникает. Но почему происходит ошибка, если я использую %f?

#include <stdio.h>

int main(void)
{
    long double num;
    printf("value: ");
    scanf("%f",&num);  // If I use %lf or %Lf instead of %f, no error occurs. 
    printf("value: %f \n",num);
}
Автор: Jin Источник Размещён: 18.07.2016 02:31

Ответы (2)


6 плюса

180540 Репутация автора

Решение

%fпредназначен для чтения floats, а не doubles или long doubles.

%lfпредназначен для использования для чтения doubleс.

%Lfпредназначен для использования для чтения long doubleс.

Если ваша программа работает с %lfтипом переменной long double, это только совпадение. Это работает, вероятно, потому sizeof(double)что так же, как sizeof(long double)на вашей платформе. Теоретически, это неопределенное поведение.

Автор: R Sahu Размещён: 18.07.2016 02:35

0 плюса

919 Репутация автора

Просматривая справочную страницу для printf(3)системы FreeBSD (кстати, POSIX), я получаю следующее:

Следующие модификаторы длины справедливо для a, A, e, E, f, F, g, или Gконверсии:

     Modifier    a, A, e, E, f, F, g, G
     l (ell)     double (ignored, same behavior as without it)
     L           long double

Я использовал преобразования с 32-разрядным типом данных с плавающей запятой. Но проблема в том, что причина в том, что разные форматы с плавающей запятой имеют разные размеры, и printfфункция должна знать, какой это формат, чтобы она могла правильно выполнить это преобразование. Использование %Lfс плавающей точкой может вызвать ошибку сегментации, потому что преобразование обращается к данным вне переменной, поэтому вы получаете неопределенное поведение.

  • поплавок: 32-разрядный
  • двойной: 64-битный
  • длинный двойной: 80 бит

Теперь long doubleфактический размер определяется платформой и реализацией. 80 бит - это 10 байтов, но это не совсем вписывается в 32-битное выравнивание без заполнения. Таким образом, большинство реализаций используют 96-битные или 128-битные (12 байтов или 16 байтов соответственно) для установки выравнивания.

Но будьте осторожны, потому что это может занять 128 бит, но это не значит, что это __float128(если вы используете gcc или clang). Существует, по крайней мере, одна платформа, где указание long doubleозначает a __float128(SunOS, я думаю), но оно реализовано в программном обеспечении и медленно. Кроме того, некоторые компиляторы (Microsoft и Intel приходят на ум) long double= doubleесли вы не укажете переключатель в командной строке.

Автор: Daniel Rudy Размещён: 18.07.2016 05:00
Вопросы из категории :
32x32