我想存储一个字符(为了与其他字符进行比较)。
如果我声明变量如下:
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 ='é';
我错过了什么吗?谢谢;)
答案 0 :(得分:3)
尝试使用wchar_t
而不是char
。 char
是单字节,适用于ASCII,但不适用于UTF-8等多字节字符集。另外,将字符文字标记为宽字符而不是窄字符:
#include <wchar.h>
...
wchar_t c = L'é';
答案 1 :(得分:2)
é
的Unicode代码点为0xE9,UTF-8编码为"\xc3\xa9"
。
我假设你的源文件是用UTF-8编码的,所以
char c = 'é';
(大致)等同于
char c = '\xc3\xa9';
如何处理这些字符常量是实现定义的。 For GCC:
编译器一次评估一个字符的多字符字符常量,将前一个值左移每个目标字符的位数,然后在截断到宽度的新字符的位模式中一个目标角色。最终的位模式为int类型,因此无论单个字符是否有符号都是有符号的(与版本3.1及更早版本的GCC略有不同)。如果常量中的字符数多于目标int中的符号,则编译器会发出警告,并忽略多余的前导字符。
例如,&#39; ab&#39;对于具有8位字符的目标,将被解释为
(int) ((unsigned char) 'a' * 256 + (unsigned char) 'b')
,将'\234a'
解释为(int) ((unsigned char) '\234' * 256 + (unsigned char) 'a')
。
因此,'é'
的值为0xC3A9,适合int
(至少为32位int
),但不适合(8位){{1 }},所以转换为char
再次implementation-defined:
为了转换为宽度为N的类型,将该值减去模2 N 以在该类型的范围内;没有信号被提出。
这给出了(带有签名的char
)
char
输出:
#include <stdio.h>
int main(void) {
printf("%d %d\n", 'é', (char)'é');
if((char)'é' == (char)'©') puts("(char)'é' == (char)'©'");
}
50089是0xC3A9,87是0xA9。
因此,当您将50089 -87
(char)'é' == (char)'©'
存储到é
时,您会丢失信息(char
等字符比较等于©
)。你可以
é
,一种依赖于实现的宽字符类型,在Linux上持有UTF-32为4字节:wchar_t
。您可以将它们转换为特定于语言环境的多字节编码(可能是UTF-8,但您需要先设置语言环境,请参阅wchar_t c = L'é';
;注意,更改语言环境可能会更改函数的行为例如setlocale
或isalpha
)printf
或直接使用它们并使用宽字符串(使用wcrtomb
前缀来获取宽字符串文字)L
或const char *c = "é";
或const char *c = "\u00e9";
,可能有不同的语义;对于C11,也许还要查找 UTF -8字符串文字和const char *c = "\xc3\xa9;"
前缀)请注意,文件流具有方向(参见u8
)。
HTH