关于printf的法律论据的几个问题(“%s”,......)

时间:2012-08-31 21:04:24

标签: c printf variadic-functions abi

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

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

    我猜不,因为0是int。但随后这提示了这个问题:

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

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

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

    我的猜测是类型并不重要,但我不确定。

3 个答案:

答案 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指针。