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

时间:2014-08-29 10:23:30

标签: c string utf-8 wchar-t

自:

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

2 个答案:

答案 0 :(得分:7)

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

内存中的实际字符串是

  

... c,o,n,t,a,i,n,s,' ',0xC3,0xA9,' ',w ...

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

您的系统上已对char进行了签名,这就是为什么您的字符在打印出来时会进行符号扩展(0xFFFFFF)。

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

答案 1 :(得分:4)

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

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

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

  

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

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

ffffff前缀是因为您输出的是有符号字符作为32位十六进制数字,因此它会为您扩展它。这是预期的。

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

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