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

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

 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 )?

原因很简单。 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 -clean和cast-free。

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

 float StrToFAndTerminate(char *Text) { float Num; Num = strtof(Text, &Text); *Text = '\0'; return Num; } 

在某些情况下,想做​​的事情是完全合理的。 如果endptr的类型为const char **endptr

理想情况下, endptr应该是与str的实际输入const-ness匹配的常量,但是C没有提供通过其语法指示这一点的方法。 ( Anders Hejlsberg在描述为什么const被排除在C#之外时会谈到这一点 。)