【问题标题】:Size of characters in *argv[] when passed argument from command line [duplicate]从命令行传递参数时*argv []中的字符大小[重复]
【发布时间】:2019-09-16 17:13:04
【问题描述】:

我有简单的程序。

#include <stdio.h>
#include <string.h

int main(int argc, char *argv[])
{   
    for (int i = 0; i < strlen(argv[1]); ++i)
        printf("%x ", argv[1][i]);
    printf("\n");
}

我喜欢运行它

$ ./program 111
31 31 31

但是当我运行它时

$ ./program ●●●
ffffffe2 ffffff97 ffffff8f ffffffe2 ffffff97 ffffff8f ffffffe2 ffffff97 ffffff8f

这里每个 应该用3 个字节(UTF-8)编码:e2978f,但看起来它是用3 个unsigned 编码的。 如果sizeof(char) 总是1 字节,我不明白ffffff 来自哪里。

【问题讨论】:

    标签: c unicode utf-8 char


    【解决方案1】:

    如果 sizeof(char) 始终为 1 字节,我不明白 ffffff 来自哪里。

    根据定义 sizeof(char) 是 1,但 '●' 不是 C 意义上的 char 并产生 3 个 char

    您的 char 是明显签名的(在您的情况下,默认情况下 char 是一个 signed char),每个输入 ● 产生每个 3 个负代码,因为您的 char 转换为 int (在您的情况下为 32b),格式 %x 考虑参数 unsigned 你有这些输出

    printf("%x", -30); 会得到相同的输出 -> ffffffe2


    注意做for (int i = 0; i &lt; strlen(argv[1]); ++i)很贵,长度不变,最好保存或直接做for (int i = 0; argv[1][i] != 0; ++i)

    最好在查看argv[1]之前检查argc是否至少为1@

    【讨论】:

    • 感谢您的宝贵意见。
    【解决方案2】:

    printf() 是一个接受可变数量参数的函数。

    任何小于int 类型的整数参数都会自动转换为int 类型。

    显然,在您的实现中,“字符”little-round-thing3 chars 组成,均具有负值。

    试试这些

    printf("%x ", (unsigned char)argv[1][i]);
    printf("%hhx ", argv[1][i]); // thanks to Jonathan Leffler
    

    【讨论】:

    • 相反,在他的实现中,char 有一个符号,并且所有多代码单元代码点仅包含 >127 的代码单元,因此在 8 位 2s 补码上为负数。
    • @Deduplicator:您的意思是strlen("little-round-thing") == 3 是指1 多代码单元代码点还是3 字符?我改变了我的答案:)
    • 是的,但这并不是真正重要的部分。
    • %hhx作为转换规范。
    • #include &lt;inttypes.h&gt;printf ("%" PRIx8 " ", (uint8_t)argv[1][i]); 使用精确宽度类型。
    【解决方案3】:

    多代码单元代码点的 UTF-8 代码单元(除 ASCII 以外的所有代码点)都在 128 到 255 之间,这意味着在 ASCII 范围之外。

    printf() 是一个可变参数函数,传递给可变参数部分的所有参数(除格式字符串之外的所有参数)都受标准提升。

    由于您的实现的裸 char 是 8 位有符号 2s 补码,这意味着 UTF-8 代码单元值是负数,并且在 -1-128 之间,升级后您将拥有一个具有该值的 int

    然后你对printf() 撒谎,断言它是unsigned%x 代表unsigned int),2 秒补码会导致你的未定义行为 打印一个很大的unsigned int

    您可以使用%hhx 获得正确的结果,但严格来说您应该将参数转换为unsigned char

    【讨论】:

      猜你喜欢
      • 2014-10-22
      • 1970-01-01
      • 2013-11-24
      • 2018-01-07
      • 2016-09-28
      • 2018-03-03
      • 2018-10-28
      • 2018-11-10
      相关资源
      最近更新 更多