我相信这实际上是 C 标准对 strchr() 函数的定义中的一个缺陷。 (我很高兴被证明是错误的。)(回复 cmets,它是否真的是一个缺陷值得商榷;恕我直言,它仍然是糟糕的设计。它可以安全使用,但是太容易了不安全地使用它。)
这是 C 标准所说的:
char *strchr(const char *s, int c);
strchr 函数定位 c 的第一次出现
(转换为 char)在 s 指向的字符串中。这
终止空字符被认为是字符串的一部分。
这意味着这个程序:
#include <stdio.h>
#include <string.h>
int main(void) {
const char *s = "hello";
char *p = strchr(s, 'l');
*p = 'L';
return 0;
}
尽管它小心地将指向字符串文字的指针定义为指向 const char 的指针,但它具有未定义的行为,因为它修改了字符串文字。至少 gcc 不会对此发出警告,并且程序会因分段错误而死。
问题在于strchr() 接受const char* 参数,这意味着它承诺不会修改s 指向的数据——但它返回一个普通的char*,它允许调用者修改相同的数据。
这是另一个例子; 它没有未定义的行为,但是它悄悄地修改了 const 限定的对象,没有任何强制转换(进一步考虑,我认为它具有未定义的行为):
#include <stdio.h>
#include <string.h>
int main(void) {
const char s[] = "hello";
char *p = strchr(s, 'l');
*p = 'L';
printf("s = \"%s\"\n", s);
return 0;
}
我认为,这意味着(回答您的问题)strchr() 的 C 实现必须强制转换其结果以将其从 const char* 转换为 char*,或执行等效操作。
这就是为什么 C++ 在它对 C 标准库所做的少数更改之一中,将 strchr() 替换为两个同名的重载函数:
const char * strchr ( const char * str, int character );
char * strchr ( char * str, int character );
当然 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 *strrchr(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 size,
int (*compar)(const void *, const void *));
(在<stdlib.h> 中声明)。所有这些函数都采用指向数组初始元素的const 数据的指针,并返回指向该数组元素的非const 指针。