我正在创建一个修改后的printf实现,我不确定这些问题的答案。
零是否作为空字符串工作? (允许printf("%s", 0)
吗?)
我猜不,因为0是int
。但随后这提示了这个问题:
NULL
是否可以作为空字符串? (允许printf("%s", NULL)
吗?)
逻辑上,我认为它应该是肯定的,因为NULL
意味着一个指针;但是很多实现似乎都有#define NULL 0
,所以我觉得在实践中可能没有。哪个是对的?
指针类型是否指向char
? (允许printf("%s", (void const *)"")
吗?)
我的猜测是类型并不重要,但我不确定。
答案 0 :(得分:8)
案例1是未定义的行为,因为参数的类型(int
)与格式说明符(char *
)所需的类型不匹配。
出于同样的原因,案例2是未定义的行为。允许将NULL
定义为值为0的任何整数常量表达式,或者将此类表达式转换为(void *)
。这些类型都不是char *
,因此行为未定义。
出于同样的原因,案例3是未定义的行为。 ""
生成一个指向以null结尾的字符数组(字符串)的有效指针,但当您将其强制转换为const void *
时,它不再具有与格式字符串匹配的正确类型。因此行为未定义。
答案 1 :(得分:0)
我相信它会编译得很好,但行为是未定义的。
关于printf
如何运作以及为什么它被认为是不安全的。
printf
需要尽可能多的参数,因为只需要一个(第一个)。然后将所有参数(第一个参数除外 - 模式)视为字节数组。它不检查类型或任何东西。它只是打印。
打印字符串更复杂,直到它找到0 byte
('\ 0')为止。为了澄清,您可以尝试使用整数进行测试。如您所知,short
为2字节长,long
为4,long long
为8.如果您告诉printf打印long
并传递2 short
s - 它会将它们视为一个long
。或者,如果您通过long long
并告诉它打印long
,则需要4个第一个字节并将其用于打印。
在我的这些特定情况下,可能(没有测试)打印什么,但它被认为是未定义的行为。如果这些值不是0,如果你传递了一些特定的值,它们可能会打印一些字符,这些值在开头有几个非'\0'
s。
不太确定它是否有帮助,但希望如此。
答案 2 :(得分:0)
来自在线C11 draft:
7.21.6.1 fprintf函数
...
s
如果不存在l
长度修改器,则参数应为指向初始值的指针 字符数组的元素。 280) 数组中的字符是 写入(但不包括)终止空字符。如果 精度是指定的,不超过写入的多个字节。如果 精度没有指定或大于数组的大小,数组应该 包含空字符。
280)对多字节字符没有特殊规定。
除了指向包含至少1个字符(0终结符)的char
数组的第一个元素的指针之外的任何内容都会调用未定义的行为。
如果您正在构建自己的实现,那么您当然可以为0或NULL定义自己的行为。
哦,就NULL的定义而言:
6.3.2.3指针
...
3一个整数常量表达式,其值为0,或者此类表达式强制转换为类型 void *,称为空指针常量。 66) 如果将空指针常量转换为a 指针类型,结果指针,称为空指针,保证比较不等 指向任何对象或函数的指针。
66)宏NULL在< stddef.h>中定义。 (和其他标题)作为空指针常量;见7.19
基本上,指针上下文中的任何0值整数表达式都被视为NULL指针。