При преобразовании двойного числа в строку, каким может быть первый символ строки? - PullRequest
3 голосов
/ 29 сентября 2019

При преобразовании двойного числа в строку, например, так:

static void strfromdouble(char *buf, size_t n, double d) {
    snprintf(buf, n, "%.14g", d);
}

Какие символы могут заканчиваться на buf[0] после вызова snprintf?

Очевидно, это может бытьодин из следующих: 0-9, -, ., но так как здесь используется математика с плавающей запятой, возможно, есть и другие символы, которые могут оказаться в buf[0], например I для Inf или N для NaN и, может быть, даже больше?

Стандартизировано ли поведение snprintf в этой ситуации для разных компиляторов и платформ? Если да, то где находится спецификация, т.е. где я могу найти, с какими символами мой код должен иметь дело в buf[0]?

1 Ответ

1 голос
/ 30 сентября 2019

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

Легко генерировать "0123456789-+ iInN". Но возможны и другие char, в зависимости от того, как далеко мы хотим его растянуть.

Очевидно, это может быть одно из следующих: 0-9, -, ., но так какздесь мы используем математические операции с плавающей запятой, возможно, есть больше символов, которые могут оказаться в буфере [0], например I для Inf или N для NaN и, возможно, даже больше?

snprintf(buf, n, "%.14g", d);

Когда n = 1, ожидайте buf[0] == '\0'

Когда n = 0, ожидайте, что buf[0] не изменится, поэтому любой *Здесь возможно значение 1032 * char.

С "%.14g" Я бы не ожидал 'I' или 'N', но 'i' и 'n'.
"%.14G" будет производить 'I' и 'N'.
С этим форматом не начинается '.'.

С другими локалями , (исследование setlocale()), '-' можетбыть чем-то другим. Я не знаю ни одной локали, которая бы это делала.

Другие форматы

С другим форматом "% something [gefaGefa]" строки:

Первый символ может бытьпробел ' ' или '+'. Как и '-', это может варьироваться в зависимости от locale .

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


При использовании форматов, специфичных для реализации, возможен любой начальный символ.

В недопустимых форматах возможен любой начальный символ из-за неопределенного поведения .


#include <stdio.h>

int main(void) {
  char s[1000];
  double inf = strtod("inf", 0);
  double nan = strtod("nan", 0);
  snprintf(s, sizeof s, "%g\n", 0.0);   printf("%3d %.1s\n", s[0], s);
  snprintf(s, sizeof s, "%g\n", 9.0);   printf("%3d %.1s\n", s[0], s);
  snprintf(s, sizeof s, "%g\n", -1.0);  printf("%3d %.1s\n", s[0], s);
  snprintf(s, sizeof s, "%+g\n", +1.0); printf("%3d %.1s\n", s[0], s);
  snprintf(s, sizeof s, "%g\n", inf);   printf("%3d %.1s\n", s[0], s);
  snprintf(s, sizeof s, "%G\n", inf);   printf("%3d %.1s\n", s[0], s);
  snprintf(s, sizeof s, "%g\n", nan);   printf("%3d %.1s\n", s[0], s);
  snprintf(s, sizeof s, "%G\n", nan);   printf("%3d %.1s\n", s[0], s);
  snprintf(s, sizeof s, "%5g\n", 1.0);  printf("%3d %.1s\n", s[0], s);
  snprintf(s, 1, "%g\n", 1.0);          printf("%3d %.1s\n", s[0], s);
  s[0] = 'z';
  snprintf(s, 0, "%g\n", 1.0);          printf("%3d %.1s\n", s[0], s);
  return 0;
}

Вывод

 48 0
 57 9
 45 -
 43 +
105 i
 73 I
110 n
 78 N
 32  
  0 
122 z

Стандартизировано ли поведение snprintf в этой ситуации на разных компиляторах и платформах?

Да. Совместимые возможности включают "0123456789-+ iInN". Некоторые компиляторы могут добавлять дополнительные определенные реализации.


где находится спецификация (?)

Ищите спецификации C. Последний - C17

Где найти текущие стандартные документы C или C ++?


Подробности:

infinity --> [-]inf or [-]infinity (efga) or uppercase version (EFGA)
nan --> [-]nan or [-]nan(n-char-sequence) or uppercase prefix version

%f --> [−]ddd.ddd,if a decimal-point character appears,at least one digit appears before it.
%F --> like %f
%e --> [−]d.ddd e±dd
%e --> like %e, but with E
%g --> converted in style f or e
%G --> converted in style F or E
%a --> [−]0xh.hhhh p±d
%A --> like %a, but with X,P
...