代码之家  ›  专栏  ›  技术社区  ›  none

在C中,将非Ascii字符转换为int,额外的位由1而不是0补充

  •  0
  • none  · 技术社区  · 8 年前

    在用C编码时,我意外地发现,对于非Ascii字符,在将其从 char (1字节)至 int (4字节),额外位(3字节)由1而不是0补充。(对于Ascii字符,额外位由0补充。)例如:

    char c[] = "ā";
    int i = c[0];
    printf("%x\n", i);
    

    ffffffc4 而不是 c4 它本身(is的UTF-8代码 \xc4\x81

    >>

    char c[] = "ā";
    unsigned int u_c;
    int i = c[0];
    unsigned int u_i = c[0];
    
    c[0] = (unsigned int)c[0] >> 1; 
    u_c = (unsigned int)c[0] >> 1;      
    i = i >> 1;
    u_i = u_i >> 1;
    printf("c=%x\n", (unsigned int)c[0]); // result: ffffffe2. The same with the signed int i.
    printf("u_c=%x\n", u_c); // result: 7fffffe2.
    printf("i=%x\n", i); // result: ffffffe2.
    printf("u_i=%x\n", u_i); // result: 7fffffe2. 
    

    现在我对这些结果感到困惑……它们是与char、int和unsigned int的数据结构有关,还是与我的操作系统(ubuntu 14.04)有关,还是与ANSI C要求有关?我试图用gcc(4.8.4)和clang(3.4)编译这个程序,但没有什么不同。

    1 回复  |  直到 8 年前
        1
  •  5
  •   Antti Haapala -- Слава Україні    8 年前

    定义的实现 是否 char 烧焦 通常是 ; 手臂上通常是一个 无符号整数类型 .

    有符号整数将为

    转换为的有符号整数 将使用模运算来包装 将值放入无符号类型的范围中,就像通过重复添加或减去无符号类型的最大值+1一样。


    unsigned char 如果您希望值为 便携式 零扩展,或用于存储范围内的小整数 0..255

    -127..127/128 使用 signed char .

    烧焦 如果签名不重要,那么实现可能会选择对平台最有效的类型。


    unsigned int u_c; u_c = (uint8_t)c[0];,
    

    自从 -0x3c -60 不在范围内 uint16_t ,则实际值为 这属于 uint16\U t ; 看,我们加减 UINT16_MAX + 1 注意,整数提升在这里可能会起作用,因此在C代码中可能需要强制转换 )直到值在范围内。 UINT16_MAX 自然总是 0xFFFFF ; 添加1以获取 0x10000 . 0x10000 - 0x3C 0xFFC4 你看到的。然后是 uint32_t 价值

    你是在一个平台上运行的吗 unsigned ,结果会是 0xC4


    BTW输入 i = i >> 1; i 是带符号的整数 负值 implementation-defined ,因此实际行为可能会因编译器而异。这个 GCC manuals state 那个

    >> 作用于负数 标志扩展

    然而,严格一致的程序不应依赖于此。