Почему для параметра endptr указывается strtof и strtod указатель на неконстантный указатель на символ? - PullRequest
22 голосов
/ 06 октября 2010

Стандартные функции библиотеки C strtof и strtod имеют следующие подписи:

float strtof(const char *str, char **endptr);
double strtod(const char *str, char **endptr); 

Каждая из них разбивает входную строку str на три части:

  1. Начальная, возможно, пустая, последовательность пробелов
  2. «Предметная последовательность» символов, представляющих значение с плавающей запятой
  3. «Завершающая последовательность» символов, которые не распознаются (и которые не влияют на преобразование).

Если endptr не NULL, то *endptr устанавливается на указатель на символ, следующий сразу за последним символом, который был частьюпреобразование (другими словами, начало конечной последовательности).

Мне интересно: почему endptr, то указатель на не- const charуказатель?Разве *endptr не является указателем на строку const char (входная строка str)?

Ответы [ 2 ]

11 голосов
/ 06 октября 2010

Причина в простоте использования. char * может автоматически преобразовываться в const char *, но char ** не может автоматически преобразовываться в const char **, и фактический тип указателя (чей адрес передается), используемый вызывающей функцией, с большей вероятностью будет char * чем const char *. Причина, по которой это автоматическое преобразование невозможно, заключается в том, что существует неочевидный способ, с помощью которого можно удалить квалификацию const через несколько этапов, где каждый шаг выглядит совершенно корректным и правильным сам по себе. Стив Джессоп привел пример в комментариях:

если бы вы могли автоматически конвертировать char** в const char**, то вы могли бы сделать

char *p;
char **pp = &p;
const char** cp = pp;
*cp = (const char*) "hello";
*p = 'j';.

Для обеспечения безопасности const одна из этих строк должна быть недопустимой, а поскольку все остальные операции выполняются совершенно нормально, это должно быть cp = pp;

Намного лучше было бы определить эти функции, взяв void * вместо char **. И char **, и const char ** могут автоматически преобразовываться в void *. (пораженный текст был на самом деле очень плохой идеей; он не только предотвращает какую-либо проверку типов, но C фактически запрещает объекты типа char * и const char * для псевдонима.) В качестве альтернативы, эти функции могли бы принимать аргумент ptrdiff_t * или size_t *, чтобы сохранить смещение конца, а не указатель на него. В любом случае это часто более полезно.

Если вам нравится последний подход, не стесняйтесь писать такую ​​обертку вокруг стандартных функций библиотеки и вызывать вашу обертку, чтобы оставшаяся часть кода была const чистой и не содержащей приведений.

5 голосов
/ 06 октября 2010

Юзабилити.Аргумент str помечен как const, поскольку входной аргумент не будет изменен.Если бы endptr было const, то это указывало бы вызывающему абоненту , что он не должен изменять данные, на которые ссылается endptr, на выходе, но часто вызывающий абонент хочет сделать именно это.Например, я могу захотеть завершить строку нулем после извлечения из нее числа с плавающей запятой:

float StrToFAndTerminate(char *Text) {
    float Num;

    Num = strtof(Text, &Text);
    *Text = '\0';
    return Num;
}

Совершенно разумная вещь, которую нужно сделать, в некоторых обстоятельствах.Не работает, если endptr имеет тип const char **.

В идеале, endptr должен иметь константность, совпадающую с фактической константой ввода str, но C не предоставляет способауказывая это через его синтаксис.( Андерс Хейлсберг говорит об этом , когда описывает, почему const был исключен из C #.)

...