strchr 实现是如何工作的 [英] How does strchr implementation work
问题描述
我尝试编写自己的 strchr() 方法实现.
现在看起来像这样:
char *mystrchr(const char *s, int c) {而 (*s != (char) c) {如果 (!*s++) {返回空值;}}返回 (char *)s;}
最后一行原来是
return s;
但这不起作用,因为 s 是 const.我发现需要这个演员表(char *),但老实说我不知道我在那里做什么:(有人可以解释一下吗?
相信这其实是C标准对strchr()
函数的定义存在缺陷.(我很高兴被证明是错误的.)(回复评论,它是否真的是一个缺陷是有争议的;恕我直言,它仍然是糟糕的设计.它可以安全使用,但太容易了不安全地使用它.)
这是 C 标准所说的:
char *strchr(const char *s, int c);
<块引用>
strchr 函数定位 c 的第一次出现(转换为 char)在 s 指向的字符串中.这终止空字符被认为是字符串的一部分.
这意味着这个程序:
#include <stdio.h>#include <string.h>诠释主要(无效){const char *s = "你好";char *p = strchr(s, 'l');*p = 'L';返回0;}
尽管它小心地将指向字符串字面量的指针定义为指向 const
char
的指针,但它具有未定义的行为,因为它修改了字符串字面量.至少 gcc 不会对此发出警告,并且程序会因分段错误而死.
问题在于 strchr()
采用 const char*
参数,这意味着它承诺不会修改 s
指向的数据to -- 但它返回一个普通的char*
,它允许调用者修改相同的数据.
这是另一个例子;它没有未定义的行为,但它悄悄地修改了一个 const
限定的对象,没有任何强制转换(进一步思考,我认为它具有未定义的行为):
#include <stdio.h>#include <string.h>诠释主要(无效){const char s[] = "你好";char *p = strchr(s, 'l');*p = 'L';printf("s = "%s"
", s);返回0;}
这意味着,我认为,(回答你的问题)strchr()
的 C 实现必须将其结果从 const char*
转换为char*
,或做类似的事情.
这就是为什么 C++ 在它对 C 标准库所做的少数更改之一中,将 strchr()
替换为两个同名的重载函数:
const char * strchr (const char * str, int character);char * strchr (char * str, int 字符);
当然 C 做不到.
另一种方法是将 strchr
替换为两个函数,一个采用 const char*
并返回一个 const char*
,以及另一个采用 char*
并返回 char*
.与 C++ 不同,这两个函数必须有不同的名称,可能是 strchr
和 strcchr
.
(历史上,const
是在 strchr()
已经被定义之后添加到 C 中的.这可能是保留 strchr()的唯一方法代码> 不破坏现有代码.)
strchr()
并不是唯一存在此问题的 C 标准库函数.受影响的功能列表(我认为这个列表是完整的,但我不保证它)是:
void *memchr(const void *s, int c, size_t n);char *strchr(const char *s, int c);char *strpbrk(const char *s1, const char *s2);char *strrcr(const char *s, int c);char *strstr(const char *s1, const char *s2);
(全部在<string.h>
中声明)和:
void *bsearch(const void *key, const void *base,size_t nmemb, size_t 大小,int (*compar)(const void *, const void *));
(在 <stdlib.h>
中声明).所有这些函数都采用指向数组初始元素的 const
数据的指针,并返回指向该数组元素的非 const
指针.
I tried to write my own implementation of the strchr() method.
It now looks like this:
char *mystrchr(const char *s, int c) {
while (*s != (char) c) {
if (!*s++) {
return NULL;
}
}
return (char *)s;
}
The last line originally was
return s;
But this didn't work because s is const. I found out that there needs to be this cast (char *), but I honestly don't know what I am doing there :( Can someone explain?
I believe this is actually a flaw in the C Standard's definition of the strchr()
function. (I'll be happy to be proven wrong.) (Replying to the comments, it's arguable whether it's really a flaw; IMHO it's still poor design. It can be used safely, but it's too easy to use it unsafely.)
Here's what the C standard says:
char *strchr(const char *s, int c);
The strchr function locates the first occurrence of c (converted to a char) in the string pointed to by s. The terminating null character is considered to be part of the string.
Which means that this program:
#include <stdio.h>
#include <string.h>
int main(void) {
const char *s = "hello";
char *p = strchr(s, 'l');
*p = 'L';
return 0;
}
even though it carefully defines the pointer to the string literal as a pointer to const
char
, has undefined behavior, since it modifies the string literal. gcc, at least, doesn't warn about this, and the program dies with a segmentation fault.
The problem is that strchr()
takes a const char*
argument, which means it promises not to modify the data that s
points to -- but it returns a plain char*
, which permits the caller to modify the same data.
Here's another example; it doesn't have undefined behavior, but it quietly modifies a const
qualified object without any casts (which, on further thought, I believe has undefined behavior):
#include <stdio.h>
#include <string.h>
int main(void) {
const char s[] = "hello";
char *p = strchr(s, 'l');
*p = 'L';
printf("s = "%s"
", s);
return 0;
}
Which means, I think, (to answer your question) that a C implementation of strchr()
has to cast its result to convert it from const char*
to char*
, or do something equivalent.
This is why C++, in one of the few changes it makes to the C standard library, replaces strchr()
with two overloaded functions of the same name:
const char * strchr ( const char * str, int character );
char * strchr ( char * str, int character );
Of course C can't do this.
An alternative would have been to replace strchr
by two functions, one taking a const char*
and returning a const char*
, and another taking a char*
and returning a char*
. Unlike in C++, the two functions would have to have different names, perhaps strchr
and strcchr
.
(Historically, const
was added to C after strchr()
had already been defined. This was probably the only way to keep strchr()
without breaking existing code.)
strchr()
is not the only C standard library function that has this problem. The list of affected function (I think this list is complete but I don't guarantee it) is:
void *memchr(const void *s, int c, size_t n);
char *strchr(const char *s, int c);
char *strpbrk(const char *s1, const char *s2);
char *strrchr(const char *s, int c);
char *strstr(const char *s1, const char *s2);
(all declared in <string.h>
) and:
void *bsearch(const void *key, const void *base,
size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
(declared in <stdlib.h>
). All these functions take a pointer to const
data that points to the initial element of an array, and return a non-const
pointer to an element of that array.
这篇关于strchr 实现是如何工作的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!