Как предотвратить переполнение буфера, конвертируя double в char? - PullRequest
1 голос
/ 12 мая 2010

Я преобразовываю double в строку символов:

char txt[10];
double num;

num = 45.344322345

sprintf(txt, "%.1f", num);

и использую «.1f» для сокращения десятичных разрядов до десятых.
т.е. - txt содержит 45,3

Я обычно использую точность в sprintf, чтобы буфер переполнения не переполнялся.Как я могу сделать это здесь, также обрезая десятичную дробь, без использования snprintf?

(т. Е. Если по какой-либо причине num = 345694876345.3)

Спасибо

РЕДАКТИРОВАТЬ Если num is> buffer, результат больше не имеет значения, просто не нужнохочу потерпеть крахНе уверен, что в этом случае имело бы смысл.

EDIT2 Мне следовало бы сделать более ясным, чем просто в теге, что это программа на Си.У меня проблемы с использованием snprintf в программе на Си. Я не хочу добавлять сторонние библиотеки.

Ответы [ 4 ]

5 голосов
/ 12 мая 2010

Используйте snprintf(), который сообщит вам, сколько байтов было напечатано , а не . В общем случае размер вашего массива должен быть достаточно большим, чтобы обрабатывать самое длинное строковое представление целочисленного целевого типа. Если заранее не известно, используйте malloc() (или asprintf(), который является нестандартным, но присутствует на многих платформах).

Редактировать

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

3 голосов
/ 12 мая 2010

Почему бы просто не сделать ваш буфер достаточно большим, чтобы вместить максимально возможное строковое представление типа double?

Предполагается, что 64-битное удвоение использует стандарт IEEE для арифметики с плавающей запятой, который использует 52 бита для мантиссы: 2 ^ 52 = 4,503,599,627,370,500 Итак, нам нужно 16 символов для хранения всех цифр до и после десятичной точки. 19 с учетом десятичной точки, знака и нулевого терминатора.

Я бы просто использовал размер буфера не менее 20 символов и пошел бы дальше.

Если вам нужно напечатать двойное число с использованием научной записи, вам нужно будет добавить достаточно места для экспоненты. Предполагая, что показатель степени со знаком 11 битов, это еще 4 символа для показателя степени плюс знак для показателя степени и буква «E». Я бы просто использовал 30 символов в этом случае.

2 голосов
/ 12 мая 2010

Если вам абсолютно необходимо сделать это самостоятельно, посчитайте цифры в числе, прежде чем пытаться конвертировать:

int whole = num;
int wholeDigits = 0;
do {
    ++wholeDigits;
}
while (whole /= 10);

double fraction = num - (int) num;
int decimallDigits = 0;
while (fraction > 0) {
    ++decimalDigits;
    fraction *= 10;
    fraction = fraction - (int) fraction;
}

int totalLength = decimalDigits ? wholeDigits + decimalDigits + 1 : wholeDigits;

Вам, вероятно, следует убедиться, что этот специальный код работает так, как было объявлено, прежде чем полагаться на него для защиты от сбоев. Я рекомендую вам использовать snprintf или что-то подобное вместо моего кода, как говорили другие.

1 голос
/ 12 мая 2010

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

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