为什么endptr参数是strtof和strtod一个指向非const char指针的指针?

时间:2010-10-06 15:31:52

标签: c const-correctness std

标准C库函数strtofstrtod具有以下签名:

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

它们将输入字符串str分解为三个部分:

  1. 一个初始的,可能是空的空格序列
  2. 表示浮点值的字符“主题序列”
  3. 无法识别(并且不影响转化)的字符的“尾随序列”。
  4. 如果endptr不是NULL,则*endptr被设置为指向紧跟在转换的最后一个字符之后的字符的指针(换句话说,尾随序列)。

    我想知道:为什么endptr是指向const char指针的指针? *endptr不是指向const char字符串(输入字符串str)的指针吗?

2 个答案:

答案 0 :(得分:11)

原因仅仅是可用性。 char *可以自动转换为const char *,但char **无法自动转换为const char **,并且调用函数使用的指针(其地址已通过)的实际类型为更有可能是char *而不是const char *。这种自动转换不可能的原因是,有一种非显而易见的方法可以通过几个步骤来删除const限定,其中每个步骤看起来完全有效并且本身是正确的。 Steve Jessop在评论中提供了一个例子:

  

如果您可以自动将char**转换为const char**,那么您可以

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

对于const-safety,其中一行必须是非法的,并且由于其他行都是完全正常的操作,因此必须是cp = pp;

更好的方法是定义这些函数,以void *代替char **char **const char **都可以自动转换为void *(受损文本实际上是一个非常糟糕的主意;它不仅会阻止任何类型检查,而且C实际上禁止类型为char *const char *的对象为别名。)或者,这些函数可能采用ptrdiff_t *size_t *参数来存储偏移量最后,而不是指向它的指针。无论如何,这通常更有用。

如果您喜欢后一种方法,请随意在标准库函数周围编写这样的包装器并调用您的包装器,以便保留代码const的其余部分 - 干净且无需转换。

答案 1 :(得分:5)

可用性。 str参数标记为const,因为输入参数不会被修改。如果endptrconst,那么会指示调用者他不应该更改输出中endptr引用的数据,但调用者通常只想做那。例如,我可能希望在获取浮点数后终止字符串:

float StrToFAndTerminate(char *Text) {
    float Num;

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

在某些情况下,想做​​的事情非常合理。如果endptr的类型为const char **,则无效。

理想情况下,endptr应该是与str的实际输入常量匹配的常量,但C无法通过其语法指示这一点。 (Anders Hejlsberg talks about this描述为什么const被排除在C#之外。)