10

我最近读了打印字符时会发生哪些积分促销活动?

unsigned char x=1; 
printf("%u",x); 

调用不确定的行为,因为由于格式说明%U,预计的printf一个unsigned int。但是我仍然想知道这个例子中发生了什么。

我认为积分促销规则适用于表达式printf("%u",x)x表示的值。

A.6.1积分促进

字符,短整数,或整数位字段中,所有符号或没有,或枚举类型的 对象,可以在表达式无论使用可以使用整数。 如果int可以表示原始类型的所有值,则该值将被转换为 为int;否则该值将转换为unsigned int。这个过程被称为积分 促销。

“可能被使用”是什么意思?这是否意味着'语法正确'或'是定义的行为'?

在这个例子中x如何被提升?我已阅读,它提升为int,但如果printf("%u", (int x))仍然是不确定的行为,然后我真的不明白为什么...

+1

我认为这个行为的确是有定义的,因为你提到的原因。 –

+1

[推荐观看](http://channel9.msdn.com/Series/C9-Lectures-Stephan-T-Lavavej-Core-C-/Stephan-T-Lavavej-Core-C-7-of-n) –

+1

@luserdroog:所以你认为“可能被使用”是指应该定义行为?或者我错过了你的观点? – lee77

回答

3

由于printf使用可变参数列表,整数提升应用于其整数参数。在任何正常的C实现中,整数提升将unsigned char转换为int。然后,您正在格式化int使用unsigned int的说明符,因此行为未定义。

在可能使用整数的地方使用字符与您的语句的行为未由C标准定义的事实之间没有冲突。尽管您可以使用字符来代替整数,但仍然适用有关可以使用%u打印的规则的规则。如果使用一个字符会生成一个适合于说明符的整数,则会定义该行为。如果使用一个字符会产生一个不适合于说明符的整数,那么该行为不会被C标准定义。

堆栈溢出的其他讨论认为,异常的C实现可能理论上符合C标准,而char类型(普通,有符号和无符号)的类型宽度为int。在这样的实现中,并且int不能代表unsigned char的所有值,所以unsigned char必须被提升为unsigned int。然而,这样的实现将是异乎寻常和麻烦的(特别是在处理EOF时),并且您可能在实践中忽略它。

+0

所以有两个步骤:首先,整数提升发生,因为x代表一个整数,printf使用可变参数列表。现在有两种可能性: 1)int不能表示无符号字符可以使用的所有值(这将是相当奇特的)。然后将x提升为已定义的unsigned int。 2)int可以表示无符号字符可以包含的所有值,所以x被提升为int。在这种情况下,就不会存在是(printf的范围内,而解决的va_arg宏)的定义'无符号整数<一些变量名> = '?哪一个也会被定义? – lee77

+0

仅供参考,在“讨论SO别处”是在这里:http://stackoverflow.com/questions/4664100/does-printfx-1-invoke-undefined-behavior –

+1

@ lee77:没有,不一定任何此类转让。当'printf'实现看到'%u'说明符时,它将尝试获取'unsigned int'参数的字节。它所采取的手段取决于实施。它不需要通过C赋值表达式。它可以是纯粹的组装或机器语言。唯一可以依赖的规则是:如果使用'unsigned int'说明符,则必须传递'unsigned int'。 –

1

如果平台的int可以代表比unsigned char所有的值就可以了,那么推广是到int,否则到unsigned int。所以这取决于你的平台。

至于“为什么”,那是因为您将x作为可变参数传递,并且变量参数的规则表示标准促销发生(可能是为了简化实现)。

+0

所以你说在上面的语境中“可能被使用”的意思是'句法正确'?或者它有不同的含义? – lee77

+0

促销是平台依赖的,合法性不是。 –

1

由于printf使用可变参数列表,它将通过va_arg解压缩。 C++是指va_arg规则的C标准。 C99标准规定如下:

va_arg宏展开为具有指定类型和调用中下一个参数的值的表达式。参数ap应该已经被va_startva_copy宏初始化(没有干预调用相同apva_end宏)。 va_arg宏的每个调用都会修改ap,以便依次返回连续参数的值。参数类型应为指定的类型名称,以便可以简单地通过后缀*类型来获取指向具有指定类型的对象的指针的类型。如果没有实际的一个参数,或者如果类型不与实际的一个参数的类型兼容(如晋升根据默认参数提升),该行为是不确定的,除了以下情况:

  • 一个类型是一个有符号整数类型,另一个类型是相应的无符号整数类型,并且该值可以在两种类型中表示;
  • 一种类型是指向void的指针,另一种是指向字符类型的指针。

显然,确定是否实际和预期类型匹配时整数优惠都考虑在内。第一个要点包括有符号与无符号不匹配。

由于x = 1肯定是由unsigned int一个值表示的,并且促进unsigned char产生任一signed int(如果INT_MAX >= UCHAR_MAX)或unsigned int(如果INT_MAX < UCHAR_MAX),这是完全合法的。