为什么 strtof 和 strtod 的 endptr 参数是指向非常量 char 指针的指针?
strtod 具有以下签名:
float strtof(const char *str, char **endptr);
double strtod(const char *str, char **endptr);
它们各自将输入字符串 str
分解为三个部分:
- 标准 C 库函数
strtof
和可能为空的空白序列
- 表示浮点值的字符“主题序列”
- 无法识别(且不影响转换)的字符“尾随序列”。
如果 endptr
不是 NULL
,则 *endptr
将设置为指向紧随转换中的最后一个字符之后的字符的指针 (换句话说,尾随序列的开始)。
我想知道:为什么 endptr
是一个指向非const
char
指针的指针? *endptr
不是指向 const
char
字符串(输入字符串 str
)的指针吗?
The standard C library functions strtof
and strtod
have the following signatures:
float strtof(const char *str, char **endptr);
double strtod(const char *str, char **endptr);
They each decompose the input string, str
, into three parts:
- An initial, possibly-empty, sequence of whitespace
- A "subject sequence" of characters that represent a floating-point value
- A "trailing sequence" of characters that are unrecognized (and which do not affect the conversion).
If endptr
is not NULL
, then *endptr
is set to a pointer to the character immediately following the last character that was part of the conversion (in other words, the start of the trailing sequence).
I am wondering: why is endptr
, then, a pointer to a non-const
char
pointer? Isn't *endptr
a pointer into a const
char
string (the input string str
)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
原因很简单,就是可用性。
char *
可以自动转换为const char *
,但char **
无法自动转换为const char **
,并且调用函数使用的指针(其地址被传递)的实际类型更有可能是char *
而不是const char *
。这种自动转换不可能的原因是,有一种非显而易见的方法可以通过几个步骤来删除const
限定,其中每个步骤本身看起来完全有效且正确。 Steve Jessop 在评论中提供了一个例子:更好的方法是定义这些函数以使用void *
代替字符**。
char **
和const char **
都可以自动转换为void *
。(被攻击的文本实际上是一个非常糟糕的文本) idea; 它不仅阻止任何类型检查,而且 C 实际上禁止使用
char *
和const char *
类型的对象作为别名。)或者,这些函数可以采用ptrdiff_t *
或size_t *
参数,用于存储末尾的偏移,而不是指向它的指针。无论如何,这通常更有用。如果您喜欢后一种方法,请随意围绕标准库函数编写这样的包装器并调用您的包装器,以便保持代码的其余部分
const
干净且无强制转换。The reason is simply usability.
char *
can automatically convert toconst char *
, butchar **
cannot automatically convert toconst char **
, and the actual type of the pointer (whose address gets passed) used by the calling function is much more likely to bechar *
thanconst char *
. The reason this automatic conversion is not possible is that there is a non-obvious way it can be used to remove theconst
qualification through several steps, where each step looks perfectly valid and correct in and of itself. Steve Jessop has provided an example in the comments:A much better approach would have been to define these functions to take(The stricken text was actually a very bad idea; not only does it prevent any type checking, but C actually forbids objects of typevoid *
in place ofchar **
. Bothchar **
andconst char **
can automatically convert tovoid *
.char *
andconst char *
to alias.) Alternatively, these functions could have taken aptrdiff_t *
orsize_t *
argument in which to store the offset of the end, rather than a pointer to it. This is often more useful anyway.If you like the latter approach, feel free to write such a wrapper around the standard library functions and call your wrapper, so as to keep the rest of your code
const
-clean and cast-free.可用性。
str
参数被标记为const
,因为输入参数不会被修改。如果endptr
为const
,那么这将指示调用者不应更改输出时从endptr
引用的数据,但调用者通常只想这样做。例如,我可能想在取出浮点后以空值终止一个字符串:在某些情况下,这是完全合理的事情。如果
endptr
的类型为const char **
,则不起作用。理想情况下,
endptr
的常量性应与str
的实际输入常量性相匹配,但 C 没有提供通过其语法来指示这一点的方法。 (Anders Hejlsberg 在描述为什么留下const
时谈到了这一点从 C# 中出来。)Usability. The
str
argument is marked asconst
because the input argument will not be modified. Ifendptr
wereconst
, then that would instruct the caller that he should not change data referenced fromendptr
on output, but often the caller wants to do just that. For example, I may want to null-terminate a string after getting the float out of it:Perfectly reasonable thing to want to do, in some circumstances. Doesn't work if
endptr
is of typeconst char **
.Ideally,
endptr
should be of const-ness matching the actual input const-ness ofstr
, but C provides no way of indicating this through its syntax. (Anders Hejlsberg talks about this when describing whyconst
was left out of C#.)