C 为什么strtof和strtod的endptr参数是指向非常量字符指针的指针?
标准C库函数C 为什么strtof和strtod的endptr参数是指向非常量字符指针的指针?,c,libc,const-correctness,C,Libc,Const Correctness,标准C库函数strof和strod具有以下签名: float strtof(const char *str, char **endptr); double strtod(const char *str, char **endptr); 它们各自将输入字符串str分解为三个部分: 空白的初始序列,可能为空 表示浮点值的字符的“主题序列” 无法识别的字符的“尾随序列”(并且不影响转换) 如果endptr不是NULL,则*endptr设置为指向转换中最后一个字符(即尾随序列的开始)后面的字符的指针
strof
和strod
具有以下签名:
float strtof(const char *str, char **endptr);
double strtod(const char *str, char **endptr);
它们各自将输入字符串str
分解为三个部分:
endptr
不是NULL
,则*endptr
设置为指向转换中最后一个字符(即尾随序列的开始)后面的字符的指针
我想知道:
endptr
为什么是指向非const
char
指针的指针?*endptr
不是指向const
char
字符串(输入字符串str
)的指针吗char*
可以自动转换为const char*
,但是char**
不能自动转换为const char**
,调用函数使用的指针的实际类型(其地址被传递)更可能是char*
。这种自动转换不可能的原因是,有一种不明显的方法可以通过几个步骤来删除常量
限定,其中每个步骤本身看起来都非常有效和正确。Steve Jessop在评论中提供了一个例子:
如果您可以自动将char**
转换为const char**
,那么您可以这样做
char *p;
char **pp = &p;
const char** cp = pp;
*cp = (const char*) "hello";
*p = 'j';.
为了施工安全,其中一条线路必须是非法的,由于其他线路都是完全正常的操作,因此必须是cp=pp代码>
更好的方法是将这些函数定义为使用void*
代替char**
。char**
和const char**
都可以自动转换为void*
。(受攻击的文本实际上是一个非常糟糕的主意;它不仅阻止任何类型检查,而且C实际上禁止类型为char*
和const char*
的对象访问alias。)或者,这些函数可以使用ptrdiff\u t*
或size\u t*
参数来存储端点的偏移量,而不是指向它的指针。无论如何,这通常更有用
如果您喜欢后一种方法,可以围绕标准库函数编写这样一个包装器,并调用您的包装器,以便保持代码的其余部分保持干净和无强制转换。可用性。str
参数被标记为const
,因为不会修改输入参数。如果endptr
是const
,则这将指示调用者不应在输出时更改从endptr
引用的数据,但调用者通常希望这样做。例如,在从字符串中取出浮点数后,我可能希望使用null终止该字符串:
float StrToFAndTerminate(char *Text) {
float Num;
Num = strtof(Text, &Text);
*Text = '\0';
return Num;
}
在某些情况下,想要做的事情是完全合理的。如果endptr
的类型为const char**
,则不起作用
理想情况下,endptr
的常量应与str
的实际输入常量相匹配,但C无法通过其语法表示这一点。(当描述为什么C#中省略了const
)这与strchr
和friends的问题基本相同,只是这里有一个out参数指针而不是返回值。@Steve:是的,但是它比strchr
问题更大,因为如果没有显式强制转换,就无法将const
限定指针的地址传递给这些函数。这是一个有趣的问题。基本上,这意味着您可以在strtoX
函数后面隐藏从char const*
到char*
的强制转换。奇怪。@Jens:这很烦人,但在C语言中这是不可避免的,因为没有函数重载。在C++中,有两个<代码> Schchr 函数,如果输入为“代码> char *<代码>,而代码为> const char *<代码>,如果输入为“代码> const char */COD>”,则返回<代码> char */COD>。在C++标准中没有这样的代码< Strut/<代码>的重载,但我不知道它的原理。在任何人提问之前,C++中没有<代码> Sttoof ,因为它不是在C89中。搜索显示,我很长一段时间都不知道这个基本原理:“无论是char**
还是const char**
都可以自动转换为void*”我明白你的意思,使用void*
可以让用户无需强制转换就可以传入const char**
。但这也会让他们在一个充满错误的世界里无需施法。考虑到C语言的局限性,我认为最好保留基本的类型安全性,甚至是失去const-safety的代价。这不仅仅是可用性,这些函数存储的结果是指针,你不能写入常量内存。“如果有人拥有它,请发布。”-如果您可以自动将char**
转换为const char**
,则可以执行char*p;字符**pp=&p;常量字符**cp=pp*cp=(常量字符*)“你好”*p='j'代码>。为了施工安全,其中一条线路必须是非法的,由于其他线路都是完全正常的操作,因此必须是cp=pp代码>。偏移量当然可以解决常量问题,尽管现在在整个库中一致使用该约定为时已晚,而且在const
发明时它可能已经太破坏性了,我不确定。如果字符串处理函数返回偏移量而不是指针是正常的,那么strcpy是否总是返回0?;-)理想情况下str