非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
时会丢失信息(有些字符比如等于é
)。 您可以
- 使用
wchar_t
,一个依赖于实现的宽字符类型,在Linux上持有UTF-32为4字节:wchar_t c = L'é';
。 您可以将它们转换为特定于语言环境的多字节编码(可能是UTF-8,但您需要先设置语言环境,请参阅setlocale
;注意,更改语言环境可能会改变函数的行为,如isalpha
或printf
)wcrtomb
或直接使用它们并使用宽字符串(使用L
前缀获取宽字符串文字) - 使用字符串并在其中存储UTF-8(如
const char *c = "é";
或const char *c = "\u00e9";
或const char *c = "\xc3\xa9;"
,可能不同语义;对于C11,也许还要查找UTF-8字符串文字和u8
前缀)
请注意,文件流具有方向 (参见fwide
)。
HTH
尝试使用wchar_t
而不是char
。 char
是单字节,适用于ASCII,但不适用于UTF-8等多字节字符集。 另外,将字符文字标记为宽字符而不是窄字符:
#include ... wchar_t c = L'é';