非ASCII字符声明

时间:2014-08-02 23:49:26

标签: c character special-characters

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

如果我声明变量如下:

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 ='é';

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

2 个答案:

答案 0 :(得分:3)

尝试使用wchar_t而不是charchar是单字节,适用于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等字符比较等于©)。你可以

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

    HTH