【问题标题】:What if i try to print large ints using %c and %s?如果我尝试使用 %c 和 %s 打印大整数怎么办?
【发布时间】:2019-09-26 08:55:33
【问题描述】:

如果我尝试打印 C 中给出的 1000:

printf("%c\n",1000);
printf("%s\n",1000);

输出会是什么?或者两行都会出错?

【问题讨论】:

  • 为什么不直接运行代码看看会发生什么?
  • @B001ᛦ 显示分段错误
  • @B001ᛦ:在一种 C 实现上尝试代码仅显示了一种 C 实现在测试的特定情况下的作用。它没有解释 C 标准定义的语义或其他规则。

标签: c string character


【解决方案1】:
printf("%c\n",1000);

%c 需要int 类型的参数(到目前为止,很好)并将其打印为字符。 1000(几乎可以肯定)在charunsigned char 的范围之外,但是

如果不存在 l 长度修饰符,则转换 int 参数 到unsigned char,然后写入生成的字符。

转换为无符号整数类型定义明确;它以 UCHAR_MAX+1 为模减少。假设UCHAR_MAX==255(几乎可以肯定是)转换的结果是(unsigned char)232,因此它将(尝试)打印字符232。结果可能取决于语言环境。您可能会遇到问题,因为 232 (0xe8) 是无效的 UTF-8 编码。

printf("%s\n",1000);

%s 需要char* 类型的参数。所以行为是未定义的。 (在实践中可能发生的情况是,值 1000 被视为指针。这不太可能是有效地址,或者从该地址开始存在有效字符串。)

【讨论】:

    【解决方案2】:

    对 printf 使用错误的格式说明符会引发未定义的行为错误,这意味着任何事情都可能发生。思考为什么你会得到某种未定义的行为不会给你太多有意义的知识,但无论如何......

    printf("%s\n",1000); 的情况下,您只是对编译器撒谎并告诉它1000 是指向已分配字符串的指针。很难确切知道会发生什么——也许编译器会跑到地址 1000 并尝试访问它,可能会导致崩溃。

    printf("%c\n",1000); 的情况下,这实际上是偶然的某种确定性行为。 printf 等可变参数函数的所有参数都会被隐式提升。如果您传递了char,它会被提升为int,然后转换回char

    但是你传递了1000 类型的整数常量int。碰巧的是,printf 在隐式提升之后需要一个int,它会尝试将1000“返回”转换为char。这意味着编译器将抓取int 的最低有效字节并将其视为char(或挑剔,视为unsigned char)。

    1000 == 0x000003E8char 转换将获取最不重要的 E8 字节。然后打印该字符在符号表中表示的任何内容,如果有的话。

    【讨论】:

    • 我不认为这种行为是未定义的。它完全按照你说的做,它试图访问地址 1000。我认为这是很好的定义
    • @RoQuOTriX 在 printf("%s\n",1000); 的情况下,如果指针是 64 位且 int 是 32 位,则只有 4 个字节将被压入堆栈。然而printf 函数希望找到一个 8 字节的指针,而其他 4 字节的内容是未知的。
    • @RoQuOTriX 如果使用了错误的格式说明符,则行为未定义。见stackoverflow.com/questions/16864552/…
    • @EricPostpischil 已修复。我没有详细检查 printf 关于%c 的说法,它确实说存在从intunsigned char 的隐式转换。在这种情况下,字节顺序确实无关紧要。
    【解决方案3】:

    请参考 printf 格式说明符:http://www.cplusplus.com/reference/cstdio/printf/

    %c - 用于打印一个字符 (char),它的值通常在 -128 到 127 之间(也可以是 0 到 255)

    %s - 用于打印chars 的数组,最后一个字符为NULL (\0)

    所以printf("%c\n",1000); 表现出实现定义的行为,因为 1000 大于 128(或 255)。

    并且printf("%s\n",1000); 正在尝试打印位于地址 1000 的字符数组(这很可能是错误的)。这也是未定义的行为,所以任何事情都可能发生。

    如果你想打印一个整数,你应该使用%d,像这样:

    printf("%d\n",1000);
    

    【讨论】:

    • printf("%c\n",1000); 没有未定义的行为。 int 参数转换为 unsigned char。看我的回答。
    • @KeithThompson 同意。我应该说它是实现定义的。
    • 另外,char 的范围不一定是 0-255。在桌面系统上,-128 到 127 是最常见的。
    • @Lundin 确实如此。这就是为什么我说“通常”。我相应地修正了答案。
    • @Lundin:在这种情况下,普通char 的签名是无关紧要的。该标准特别指出 int 参数转换为 unsigned char,其范围为 0..255 除非您使用的是带有 CHAR_BIT > 8 的特殊系统(很可能是 DSP) .此外,将超出范围的整数转换为无符号类型是明确定义的,这与将超出范围的整数转换为有符号类型不同。
    猜你喜欢
    • 2011-07-27
    • 2013-06-30
    • 2022-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-20
    • 1970-01-01
    相关资源
    最近更新 更多