关于编码签名/未签名的字符C问题

时间:2010-03-26 15:05:25

标签: c utf-8 char

我读到C没有定义char是有符号还是无符号,并且在GCC页面中这表示它可以在x86上签名并且在PowerPPC和ARM中无符号。

Okey,我正在用GLIB编写一个程序,将char定义为gchar(不超过它,只是标准化的一种方式)。

我的问题是,UTF-8怎么样?它使用的不仅仅是一块内存吗?

说我有一个变量

  

unsigned char * string =“我的字符串,带有UTF8 enconding~>çã”;

如果我将变量声明为

,请参阅
  

无符号

我只有127个值(所以我的程序会存储更多的mem块)或者UTF-8也会变为负值?

很抱歉,如果我无法正确解释,但我认为我有点复杂。

注意: 谢谢你的回答

我不明白它是如何正常解释的。

我认为就像ascii一样,如果我的程序中有一个带符号和无符号的字符,那么字符串就会有不同的值,这会导致混淆,想象一下它在utf8中。

8 个答案:

答案 0 :(得分:6)

我有几个要求解释我发表的评论。

当您比较字符并期望某个排序时,char类型可以默认为有符号或无符号类型这一事实可能很重要。特别是,UTF8使用高位(假设char是8位类型,在绝大多数平台中都是如此),以指示字符代码点需要表示多个字节。 / p>

问题的一个快速而肮脏的例子:

#include <stdio.h>
int main( void)
{
    signed char flag = 0xf0;
    unsigned char uflag = 0xf0;

    if (flag < (signed char) 'z') {
        printf( "flag is smaller than 'z'\n");
    }
    else {
        printf( "flag is larger than 'z'\n");
    }    


    if (uflag < (unsigned char) 'z') {
        printf( "uflag is smaller than 'z'\n");
    }
    else {
        printf( "uflag is larger than 'z'\n");
    }
    return 0;
}

在我工作的大多数项目中,通常使用明确指定char的typedef来避免使用未加修饰的unsigned char类型。类似uint8_t

中的stdint.h
typedef unsigned char u8;

一般来说处理unsigned char类型似乎运行良好并且几乎没有问题 - 我偶然遇到的一个问题是使用那种类型的东西来控制循环:

while (uchar_var-- >= 0) {
    // infinite loop...
}

答案 1 :(得分:5)

使用unsigned char有其优点和缺点。最大的好处是你没有得到符号扩展或其他有趣的功能,如签名溢出,这会产生意外的计算结果。无符号字符也与&lt; cctype&gt;兼容宏/函数,如isalpha(ch)(所有这些都需要unsigned char范围内的值)。另一方面,所有I / O函数都需要char *,只要你进行I / O操作就需要进行转换。

对于UTF-8,将它存储在有符号或无符号数组中是可以的,但是你必须小心那些字符串文字,因为它们几乎不能保证它们是有效的UTF-8。 C ++ 0x添加了UTF-8字符串文字以避免可能出现的问题,我希望下一个C标准也可以采用这些文字。

一般情况下,只要确保源代码文件始终采用UTF-8编码,就应该没问题。

答案 2 :(得分:4)

两件事:

  1. char类型是有符号还是无符号不会影响您将UTF8编码字符串转换为您正在使用的任何显示字符串类型(WCHAR或其他)的能力。不要担心,换句话说:UTF8字节只是字节,无论你使用什么作为编码器/解码器都会做正确的事情。

  2. 您的一些困惑可能是您尝试这样做:

    unsigned char *string = "This is a UTF8 string";
    

    不要这样做 - 你混合了不同的概念。 UTF-8编码的字符串只是一个字节序列。 C字符串文字(如上所述)并没有真正用于表示这一点;它们旨在表示“ASCII编码”字符串。虽然在某些情况下(比如我的),它们最终会成为同一个东西,但在问题的例子中,它们可能不会。当然在其他情况下他们不会。从外部资源加载Unicode字符串。一般来说,我要警惕在.c源文件中嵌入非ASCII字符;即使编译器知道如何处理它们,工具链中的其他软件也可能不会。

答案 3 :(得分:2)

signed / unsigned只影响算术运算。如果char是无符号的,那么更高的值将是正数。如果签字,他们将是负面的。但范围仍然相同。

答案 4 :(得分:1)

实际上,unsigned / signed未指定变量可容纳的值。它指定了解释的方式。

因此,unsigned charsigned char具有相同数量的值,除了一个具有负数而另一个不具有负数。它仍然是8位(如果我们假设char保持8位,我不确定它到处都有。)

答案 5 :(得分:1)

将char *用作字符串时没有区别。签名/未签名的唯一时间会产生影响,如果您将其解释为数字,例如算术,或者您将其打印为整数。

答案 6 :(得分:0)

不能假定

UTF-8个字符存储在一个字节中。 UTF-8字符可以是1-4字节宽。因此,charwchar_tsignedunsigned不足以假设一个单位总是可以存储一个UTF-8字符。

大多数平台(例如PHP,.NET等)都可以正常构建字符串(例如C中的char[])并使用库在字符串之间转换编码和解析字符。 / p>

答案 7 :(得分:0)

关于你的问题:

  

如果我有一个烧焦或未签名的字符阵列可以让我的程序运行错误? - drigoSkalWalker

是。我做了。如果使用普通的签名字符,那么从我的应用程序中看到一个简单的可运行的摘录,完全出错了。 将所有字符更改为无符号in参数后尝试运行它。像这样:

int is_valid( unsigned char c);

然后它应该正常工作。

#include <stdio.h>

int is_valid(char c);

int main() {

    char ch = 0xFE;
    int ans = is_valid(ch);
    printf("%d", ans);

}

int is_valid(char c) {
    if((c == 0xFF) || (c == 0xFE)) {
    printf("NOT valid\n");
        return 0;
    }
    else {
        printf("valid\n")
        return 1;
    }
}  

它的作用是验证char是否是utf-8中的有效字节。 0xFF和0xFE在utf-8中不是有效字节。 如果函数将其验证为有效字节,请设想问题?

这是怎么回事:

0xFE
= 
11111110 
= 
254

如果将其保存在普通字符(已签名)中,则最左边的位(最高位)使其为负数。但它的负数是多少?

它通过翻转位并添加一位来实现。

11111110
00000001
00000001 + 00000001 =
00000010 = 2

并且记住它使它变为负数,因此变为-2

所以(-2 == 0xFE)在函数中是不正确的。 同样适用于(-2 == 0xFF)。

因此,检查无效字节的函数最终会验证无效字节,就像它们没问题一样:-o。

在处理utf-8时,我可以想到坚持无符号的另外两个原因是:

  1. 如果您可能需要向右移位一些,可能会有麻烦,因为如果使用签名字符,您最终可能会从左侧添加1。

  2. utf-8和unicode只使用正数,所以...为什么不这样做?保持简单:)