为什么 strtof 和 strtod 的 endptr 参数是指向非常量 char 指针的指针?

发布于 2024-09-26 04:56:33 字数 628 浏览 11 评论 0原文

strtod 具有以下签名:

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

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

  1. 标准 C 库函数 strtof可能为空的空白序列
  2. 表示浮点值的字符“主题序列”
  3. 无法识别(且不影响转换)的字符“尾随序列”。

如果 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:

  1. An initial, possibly-empty, sequence of whitespace
  2. A "subject sequence" of characters that represent a floating-point value
  3. 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

谈场末日恋爱 2024-10-03 04:56:33

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

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

<前><代码>char *p;
字符 **pp = &p;
const char** cp = pp;
*cp = (const char*) "你好";
*p = 'j';。

为了常量安全,其中一行必须是非法的,并且由于其他行都是完全正常的操作,因此它必须是 cp = pp;

更好的方法是定义这些函数以使用 void * 代替 字符**。 char **const char ** 都可以自动转换为 void *(被攻击的文本实际上是一个非常糟糕的文本) idea; 它不仅阻止任何类型检查,而且 C 实际上禁止使用 char *const char * 类型的对象作为别名。)或者,这些函数可以采用ptrdiff_t *size_t * 参数,用于存储末尾的偏移,而不是指向它的指针。无论如何,这通常更有用。

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

The reason is simply usability. char * can automatically convert to const char *, but char ** cannot automatically convert to const char **, and the actual type of the pointer (whose address gets passed) used by the calling function is much more likely to be char * than const char *. The reason this automatic conversion is not possible is that there is a non-obvious way it can be used to remove the const 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:

if you could automatically convert char** to const char**, then you could do

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

For const-safety, one of those lines must be illegal, and since the others are all perfectly normal operations, it has to be cp = pp;

A much better approach would have been to define these functions to take void * in place of char **. Both char ** and const char ** can automatically convert to void *. (The stricken text was actually a very bad idea; not only does it prevent any type checking, but C actually forbids objects of type char * and const char * to alias.) Alternatively, these functions could have taken a ptrdiff_t * or size_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.

电影里的梦 2024-10-03 04:56:33

可用性。 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 在描述为什么留下 const 时谈到了这一点从 C# 中出来。)

Usability. The str argument is marked as const because the input argument will not be modified. If endptr were const, then that would instruct the caller that he should not change data referenced from endptr 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:

float StrToFAndTerminate(char *Text) {
    float Num;

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

Perfectly reasonable thing to want to do, in some circumstances. Doesn't work if endptr is of type const char **.

Ideally, endptr should be of const-ness matching the actual input const-ness of str, but C provides no way of indicating this through its syntax. (Anders Hejlsberg talks about this when describing why const was left out of C#.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文