在printf需要一个int的情况下,是否要给printf一个char参数的UB?

问题描述

我是否正确理解该程序导致UB的标准:

#include <stdio.h>

int main(void)
{
    char a = 'A';
    printf("%c\n",a);
    return 0;
}

当它在sizeof(int)==1 && CHAR_MIN==0的系统上执行时?

由于a是无符号的,并且大小与({1)}相同(1),因此它将提升为int [1](2),而不是unsigned int,因为int不能代表int的所有值。格式说明符char期望"%c" [2],并且在int中使用错误的符号会导致UB [3]。

C99的ISO / IEC 9899相关报价

[1]根据C99 6.3.1.1:2晋升为printf()

如果int可以代表原始类型的所有值,则该值为 转换为int;否则,它将转换为int。 这些称为整数促销。所有其他类型是 不受整数促销的影响。

[2]格式说明符unsigned int需要一个"%c"参数C99 7.19.6.1:8 int

如果不存在c长度修饰符,则l参数将转换为 int,然后写入结果字符。

[3]在unsigned char(3)中使用错误的类型(包括错误的签名)会导致根据C99 7.19.6.1:9的UB:

...如果任何参数不是对应参数的正确类型 转换规范,其行为是不确定的。

fprintf()宏给出了具有不同符号的相同类型的异常,但va_arg没有给出,并且不要求printf()使用printf()(4)。

脚注: (标记为( n ))

  1. 这意味着va_arg,因为INT_MAX==SCHAR_MAX没有填充。

  2. 另请参阅以下问题:Is unsigned char always promoted to int?

  3. 相同的规则适用于char,请参见C99 7.19.6.3:2

  4. 另请参阅以下问题:Does printf("%x",1) invoke undefined behavior?

解决方法

一个程序可以具有未定义的行为,取决于实现的特征

例如,一个执行的程序

int x = 32767;
x++;

(在其他方面定义良好)在INT_MAX> 32767的实现中具有良好定义的行为,否则具有未定义的行为。

您的程序:

#include <stdio.h>

int main(void)
{
  char a='A';
  printf("%c\n",a);
  return 0;
}
对于任何使用INT_MAX >= CHAR_MAX的托管实现,

都有明确定义的行为。在任何此类实现中,'A'的值都会提升为int所期望的%c

如果INT_MAX < CHAR_MAX(这意味着纯char是无符号的且CHAR_BIT >= 16),则a的值将提升为unsigned int。 N1570 7.21.6.1p9:

如果任何参数不是对应参数的正确类型 转换规范,其行为是不确定的。

暗示这具有未定义的行为。

实际上,(a)这种实现很少见,很可能不存在(我听说过CHAR_BIT > 8的仅有的C实现是DSPs的,并且这些实现很可能是独立的), (b)任何此类实现都可能旨在优雅地处理此类情况。

,

TL; DR没有UB(以我的解释,无论如何)。

6.2.5类型
6.对于每个有符号整数类型,都有一个对应的(但不同的)无符号整数类型(用关键字unsigned表示)使用相同的存储量(包括符号信息)并且具有相同的对齐要求。 > 9.有符号整数类型的非负值范围是相应的无符号整数类型的子范围,并且每种类型中相同值的表示形式都相同 41)
41)相同的表示形式和对齐要求旨在表示与函数的参数,函数的返回值和并集成员相同的可互换性。

此外

7.16.1.1 va_arg宏
2 va_arg宏扩展为具有指定类型和调用中下一个参数值的表达式。 [...]如果没有实际的下一个自变量,或者类型与实际的下一个自变量的类型不兼容(根据默认自变量的提升),则该行为是不确定的,除了以下情况: / p>

  • 一种类型是有符号整数类型,另一种类型是相应的无符号整数类型,并且值在两种类型中均可表示;

7.21.6.8 vfprintf函数
288) [...]函数vfprintf,vfscanf,vprintf,vscanf,vsnprintf,vsprintf和vsscanf调用va_arg宏[...]

因此,只要值在范围内,就可以认为无符号类型不是不是“对应(带符号)转换规范的错误类型”。

以下事实得到了证实,即即使主要的编译器也确实警告其他不匹配,即使它们在给定平台上具有相同的表示形式(例如{{1 }}和long

,

我是否了解该程序导致UB的标准正确信息?

#include <stdio.h>

int main(void)
{
  char a='A';
  printf("%c\n",a);
  return 0;
}

何时在sizeof(int)== 1 && CHAR_MIN == 0的系统上执行?

这可能是对该标准的合理解释。但是,如果产生了具有这种类型特征组合的实现以供真正使用,则我完全有信心,它将为%c指令提供适当的支持-作为扩展,如果要解释的话这样。这样,无论C标准是否也被解释为定义该行为,示例程序都将对该实现具有明确定义的行为。我想我认为实现质量问题是“为了真正使用”而汇总的。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...