strchr 实现是如何工作的 [英] How does strchr implementation work

查看:14
本文介绍了strchr 实现是如何工作的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试编写自己的 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++ 不同,这两个函数必须有不同的名称,可能是 strchrstrcchr.

(历史上,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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆