非ASCII字符声明

我想存储一个字符(以便与其他字符进行比较)。

如果我声明这样的变量:

char c = 'é'; 

一切运作良好,但我得到这些警告:

 warning: multi-character character constant [-Wmultichar] char c = 'é'; ^ ii.c:12:3: warning: overflow in implicit constant conversion [-Woverflow] char c = 'é'; 

我想我理解为什么会有这些警告,但我想知道为什么它仍然有效? 我应该这样定义: int d = 'é'; 虽然在内存中占用更多空间? 此外,我还通过以下声明获得以下警告:

 warning: multi-character character constant [-Wmultichar] 

int d =’é’;

我错过了什么吗? 谢谢 ;)

é具有Unicode代码点0xE9,UTF-8编码为"\xc3\xa9"

我假设你的源文件是用UTF-8编码的,所以

 char c = 'é'; 

是(大致)相当于

 char c = '\xc3\xa9'; 

如何处理这些字符常量是实现定义的。 对于GCC :

编译器一次评估一个字符的多字符字符常量,将前一个值移动每个目标字符的位数,然后在截断到目标宽度的新字符的位模式中输入字符。 最终的位模式为int类型,因此无论单个字符是否有符号都是有符号的(与版本3.1及更早版本的GCC略有不同)。 如果常量中的字符数多于目标int中的字符数,则编译器会发出警告,并忽略多余的前导字符。

例如,具有8位字符的目标的’ab’将被解释为(int) ((unsigned char) 'a' * 256 + (unsigned char) 'b')'\234a' (int) ((unsigned char) '\234' * 256 + (unsigned char) 'a')

因此, 'é'的值为0xC3A9,它适合int (至少对于32位int ),但不适合(8位) char ,因此转换为char也是实现定义的 :

为了转换为宽度为N的类型,该值以2 N为模减少到该类型的范围内; 没有信号被提出。

这给了(带有签名的char

 #include  int main(void) { printf("%d %d\n", 'é', (char)'é'); if((char)'é' == (char)'©') puts("(char)'é' == (char)'©'"); } 

输出:

 50089 -87 (char)'é' == (char)'©' 

50089是0xC3A9,87是0xA9。

因此,当将é存储到char时会丢失信息(有些字符比如等于é )。 您可以

  1. 使用wchar_t ,一个依赖于实现的宽字符类型,在Linux上持有UTF-32为4字节: wchar_t c = L'é'; 。 您可以将它们转换为特定于语言环境的多字节编码(可能是UTF-8,但您需要先设置语言环境,请参阅setlocale ;注意,更改语言环境可能会改变函数的行为,如isalphaprintfwcrtomb或直接使用它们并使用宽字符串(使用L前缀获取宽字符串文字)
  2. 使用字符串并在其中存储UTF-8(如const char *c = "é";const char *c = "\u00e9";const char *c = "\xc3\xa9;" ,可能不同语义;对于C11,也许还要查找UTF-8字符串文字u8前缀)

请注意,文件流具有方向 (参见fwide )。

HTH

尝试使用wchar_t而不是charchar是单字节,适用于ASCII,但不适用于UTF-8等多字节字符集。 另外,将字符文字标记为宽字符而不是窄字符:

 #include  ... wchar_t c = L'é';