为什么`strchr`似乎与多字节字符一起工作,尽管手册免责声明?

从:

man strchr 

char * strchr(const char * s,int c);

strchr()函数返回指向字符串s中第一次出现的字符c的指针。

这里“字符”表示“字节”; 这些函数不适用于宽字符或多字节字符。

不过,如果我尝试搜索像é (UTF-8中的0xC3A9 )这样的多字节字符:

 const char str[] = "This string contains é which is a multi-byte character"; char * pos = strchr(str, (int)'é'); printf("%s\n", pos); printf("0x%X 0x%X\n", pos[-1], pos[0]); 

我得到以下输出:

这是一个多字节字符

0xFFFFFFC3 0xFFFFFFA9

尽管有警告:

警告:多字符字符常量[-Wmultichar]

所以这是我的问题:

  • 什么意味着strchr不适用于多字节字符? (它似乎工作,只要int类型足够大,包含你的多字节,最多4个字节)
  • 如何摆脱警告,即如何安全地恢复多字节值并将其存储在int中?
  • 为什么前缀为0xFFFFFF

strchr()似乎只适用于您的多字节字符。

内存中的实际字符串是

… c,o,n,t,a,i,n,s,”,0xC3,0xA9,”,w …

当你调用strchr() ,你实际上只搜索0xA9 ,它是低8位。 这就是pos[-1]具有多字节字符的第一个字节的原因:它在搜索过程中被忽略了。

在您的系统上签名一个char ,这就是为什么你打印出来时你的字符符号扩展( 0xFFFFFF )。

至于警告,似乎编译器试图告诉你,你正在做一些奇怪的事情,你就是这样。 不要忽视它。

那就是问题所在。 它似乎工作。 首先,如果你在其中放入多字节字符,它完全取决于编译器在字符串中放置的内容,如果它确实根本编译它。 显然你很幸运(对于幸运的一些恰当的解释),因为它已经填满了你的字符串

 .... c3, a9, ' ', 'w', etc 

并且你正在寻找c3a9 ,因为它可以很容易地找到它。 strchr的手册页说:

strchr()函数返回指向字符串s中第一次出现的c(转换为char)的指针

所以你将c3a9传递给它,它被转换为值为’a9’的char 。 它找到了a9字符,并返回指向它的指针。

ffffff前缀是因为您输出的是带符号的字符作为32位hex数字,因此它会为您扩展它。 这是预期的。

问题是“未定义的行为”就是这样。 它几乎可以正常工作。 它可能不会,视情况而定。

它几乎是。 你没有得到一个指向多字节字符的指针,你得到一个指向它中间的指针,(我很惊讶你把它解释为工作)。 如果多字节字符已经评估为0xff20,那么您将被指向字符串中较早的某个位置。