采用int参数是否需要%c fprintf说明符

时间:2013-07-26 14:11:03

标签: c c99 language-lawyer printf variadic-functions

第7.19.6.1节 C99标准第8段中:

  

c 如果不存在 l 长度修饰符,则会转换 int 参数到了    unsigned char ,并且会写出结果字符。

第7.19.6.1节 C99标准第9段中:

  

如果任何参数不是相应转换规范的正确类型,则行为未定义。

  • fprintf函数是否需要int参数?

例如,将unsigned int结果传递给未定义的行为:

unsigned int foo = 42;

fprintf(fp, "%c\n", foo); /* undefined behavior? */

这令我担心,因为实施可能已将char定义为与unsigned char具有相同的行为(第6.2.5节第15段)。

对于这些情况,整数提升可能会要求charpromoted to unsigned int on some implementations。因此,将以下代码留给那些实现的未定义行为风险:

char bar = 'B';

fprintf(fp, "%c\n", bar); /* possible undefined behavior? */
  • int变量和文字int常量是使用fprintf说明符将值传递给%c的唯一安全方法吗?

2 个答案:

答案 0 :(得分:5)

%c

fprintf转换规范需要int个参数。在默认参数促销之后,该值必须为int类型。

unsigned int foo = 42;
fprintf(fp, "%c\n", foo);

未定义的行为:foo必须是int

char bar = 'B';
fprintf(fp, "%c\n", bar);

未定义的行为:bar被提升(默认参数提升)到int,因为fprintf是一个可变函数。

编辑:公平地说,仍有一些非常罕见的实现,它们可能是未定义的行为。例如,如果char是一个无符号类型,且char中没有所有int值可表示(如this implementation中所示),则默认参数提升为{{1} }}

答案 1 :(得分:3)

是的,printf "%c"需要int参数 - 或多或少。

如果参数的类型比int窄,那么它将提升。在大多数情况下,促销是int,具有明确定义的行为。在极少数情况下,普通char是未签名的sizeof (int) == 1(暗示CHAR_BIT >= 16),char参数会提升为unsigned int,其中可以导致未定义的行为。

字符常量已经是int类型,因此即使在异国情调的系统上也可以很好地定义printf("%c", 'x')。 (偏离主题:在C ++中,字符常量的类型为char。)

此:

unsigned int foo = 42;
fprintf(fp, "%c\n", foo);

严格来说有未定义的行为。 N1570 7.1.4p1说:

  

如果函数的参数有...类型(促销后)没有   期望由具有可变数量的参数的函数,行为   未定义。

并且fprintf电话显然违背了这一点。 (感谢ouah指出这一点。)

另一方面,6.2.5p6说:

  

对于每个有符号整数类型,都有一个对应的(但是   另外)无符号整数类型(用关键字指定)   未签名)使用相同数量的存储空间(包括签名信息)并具有相同的对齐要求。

和6.2.5p9说:

  

有符号整数类型的非负值范围是子范围   相应的无符号整数类型,以及表示形式   每种类型的相同值都是相同的。

脚注:

  

相同的表示和对齐要求意味着暗示   可互换性作为函数的参数,返回值   职能和工会成员。

脚注表示类型intunsigned int的函数参数是可互换的,只要该值在两种类型的可表示范围内即可。 (对于典型的32位系统,这意味着该值必须在0到2 31 -1范围内; int值来自-2 31 从-1 31 到2 32 -1的{-1}和unsigned int值超出了另一种类型的范围,并且不可互换。)< / p>

但是C标准中的脚注是非规范。它们通常旨在澄清规范性文本中规定的要求,而不是强加新的要求。但是这里的规范性文本仅仅表明相应的有符号和无符号类型具有相同的表示,这不会必然暗示它们以与函数参数相同的方式传递。原则上,编译器可以忽略该脚注,例如,在不同的寄存器中传递intunsigned int个参数,使fprintf(fp, "%c\n", foo);未定义。

但实际上,没有理由让实现这种游戏,你可以依靠fprintf(fp, "%c\n", foo);按预期工作。我从未见过或听说过一个不起作用的实现。

就个人而言,我宁愿不依赖于此。如果我正在编写该代码,我会通过演员添加一个显式转换,这样就不会出现这些问题:

unsigned int foo = 42;
fprintf(fp, "%c\n", (int)foo);

或者我首先让foo成为int