在printf需要一个int的情况下,是否给UB提供char参数给UB是UB? [英] Is it UB to give a char argument to printf where printf expects a int?

查看:44
本文介绍了在printf需要一个int的情况下,是否给UB提供char参数给UB是UB?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  #include< stdio.h>int main(无效){char a ='A';printf(%c \ n",a);返回0;} 

sizeof(int)== 1&&CHAR_MIN == 0 ?

因为如果 a 是未签名的并且具有与 int 相同的大小(1),它将被提升为 unsigned int [1](2),而不是 int ,因为 int 不能代表 char 的所有值.格式说明符%c" 需要 int [2],并且在 printf()中使用错误的符号会导致UB [3].

ISO/IEC 9899中针对C99的相关报价

[1]根据C99 6.3.1.1:2升级为 int :

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

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

如果不存在 l 长度修饰符,则将 int 参数转换为 unsigned char ,并写入结果字符.

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

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

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

脚注:(标记为( n ))

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

  2. 另请参阅以下问题:未签名的char总是被提升为int?

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

  4. 另请参阅以下问题: printf("%x,1)调用未定义的行为?

解决方案

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宏[...]

因此,可以认为无符号类型不是不是对于相应的(有符号的)转换规范而言是不正确的类型",只要该值在该范围内即可.

主要编译器不会警告有符号/无符号格式说明不匹配,即使它们确实警告其他不匹配,即使相应的类型在给定平台上具有相同的表示形式(例如,long long long ).

Do I understand the standard correctly that this program cause UB:

#include <stdio.h>

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

When it is executed on a system where sizeof(int)==1 && CHAR_MIN==0?

Because if a is unsigned and has the same size (1) as an int, it will be promoted to an unsigned int [1] (2), and not to an int, since a int can not represent all values of a char. The format specifier "%c" expects an int [2] and using the wrong signedness in printf() causes UB [3].

Relevant quotes from ISO/IEC 9899 for C99

[1] Promotion to int according to C99 6.3.1.1:2:

If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions. All other types are unchanged by the integer promotions.

[2] The format specifier "%c" expects an int argument, C99 7.19.6.1:8 c:

If no l length modifier is present, the int argument is converted to an unsigned char, and the resulting character is written.

[3] Using the wrong type in fprintf() (3), including wrong signedness, causes UB according to C99 7.19.6.1:9:

... If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.

The exception for same type with different signedness is given for the va_arg macro but not for printf() and there is no requirement that printf() uses va_arg (4).

Footnotes: (marked with (n))

  1. This implies INT_MAX==SCHAR_MAX, because char has no padding.

  2. See also this question: Is unsigned char always promoted to int?

  3. The same rules are applied to printf(), see C99 7.19.6.3:2

  4. See also this question: Does printf("%x",1) invoke undefined behavior?

解决方案

TL;DR there is no UB (in my interpretation at any rate).

6.2.5 types
6. For each of the signed integer types, there is a corresponding (but different) unsigned integer type (designated with the keyword unsigned) that uses the same amount of storage (including sign information) and has the same alignment requirements.
9. The range of nonnegative values of a signed integer type is a subrange of the corresponding unsigned integer type, and the representation of the same value in each type is the same 41)
41) The same representation and alignment requirements are meant to imply interchangeability as arguments to functions, return values from functions, and members of unions.

Furthermore

7.16.1.1 The va_arg macro
2 The va_arg macro expands to an expression that has the specified type and the value of the next argument in the call. [...] If there is no actual next argument, or if type is not compatible with the type of the actual next argument (as promoted according to the default argument promotions), the behavior is undefined, except for the following cases:

  • one type is a signed integer type, the other type is the corresponding unsigned integer type, and the value is representable in both types;

7.21.6.8 The vfprintf function
288) [...] functions vfprintf, vfscanf, vprintf, vscanf, vsnprintf, vsprintf, and vsscanf invoke the va_arg macro [...]

Thus, it stands to reason that an unsigned type is not "an incorrect type for the corresponding (signed) conversion specification", as long as the value is within the range.

This is corroborated by the fact that major compilers do not warn about signed/unsigned format specification mismatch, even though they do warn about other mismatches, even when the corresponding types have the same representation on a given platform (e.g. long and long long).

这篇关于在printf需要一个int的情况下,是否给UB提供char参数给UB是UB?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆