6

我正在创建一个修改后的 printf 实现,但我不确定这些问题的答案。

  1. 零作为空字符串工作吗?(printf("%s", 0)允许吗?)

    我猜不是,因为 0 是一个int. 但是这会提示这个问题:

  2. NULL可以作为空字符串工作吗?(printf("%s", NULL)允许吗?)

    从逻辑上讲,我认为应该是的,因为NULL暗示了一个指针;但是很多实现似乎都有#define NULL 0,所以我觉得在实践中可能没有。哪个是对的?

  3. 指针类型是否必须指向char?(printf("%s", (void const *)"")允许吗?)

    我的猜测是类型无关紧要,但我不确定。

4

3 回答 3

8

情况 1 是未定义的行为,因为参数 ( int) 的类型与格式说明符 ( ) 所需的类型不匹配char *

出于同样的原因,案例 2 是未定义的行为。NULL允许将其定义为任何值为 0 的整数常量表达式,或者这样的表达式转换为(void *). 这些类型都不是char *,因此行为未定义。

出于同样的原因,案例 3 是未定义的行为。""产生一个指向以 null 结尾的字符数组(字符串)的有效指针,但是当您将其强制转换为 时const void *,它不再具有与格式字符串匹配的正确类型。因此行为是未定义的。

于 2012-08-31T21:18:25.907 回答
0

来自在线C11 草案

7.21.6.1 fprintf 函数

...
s如果不存在l长度修饰符,则参数应为指向字符类型数组的初始元素的指针。280) 数组中的字符被写入(但不包括)终止空字符。如果指定了精度,则写入的字节数不会超过这个数。如果未指定精度或大于数组的大小,则数组应包含空字符。
280) 对多字节字符没有特殊规定。

char除了指向包含至少 1 个字符(0 终止符) 的数组的第一个元素的指针之外的任何内容都会调用未定义的行为。

如果您正在构建自己的实现,您当然可以为 0 或 NULL 定义自己的行为。

哦,就 NULL 的定义而言:

6.3.2.3 指针

...
3 值为 0 的整数常量表达式,或转换为 void * 类型的此类表达式称为空指针常量。66) 如果将空指针常量转换为指针类型,则生成的指针(称为空指针)保证与指向任何对象或函数的指针不相等。
66) 宏 NULL 在 <stddef.h>(和其他头文件)中定义为空指针常量;见 7.19

基本上,指针上下文中的任何 0 值整数表达式都被视为 NULL 指针。

于 2012-09-01T14:53:10.217 回答
0

我相信它会编译得很好,但行为是不确定的。

关于如何printf工作以及为什么它被认为不安全的一些信息。 printf接受尽可能多的参数,因为您只需要一个(第一个)。然后将所有参数(第一个参数 - 模式除外)视为字节数组。它不检查类型或任何东西。它只是打印。

打印字符串更复杂,因为它会一直持续到找到0 byte('\0')。为了澄清,您可以尝试使用整数对其进行测试。如您所知,short长度为 2 个字节,long为 4 和long long8。如果您告诉 printf 打印long并传递 2 shorts - 它会将它们视为 one long。或者,如果您通过long long并告诉它 print long,它将占用 4 个第一个字节并将它们用于打印。

在我的这些特定情况下,可能(没有测试)什么都不打印,但它被认为是未定义的行为。'\0'如果这些值不是 0,如果您传递了一些在开头有几个非 s 的特定值,它可能会打印一些字符。

不太确定它是否有帮助,但希望如此。

于 2012-08-31T21:21:07.043 回答