是否在C表达式中自动提升字符?

时间:2015-09-03 19:03:08

标签: c++ c char int integer-promotion

我向我的一位同事发了言,那是:

  

"字符会自动提升为C表达式中的整数,这对性能很好,因为CPU的自然字大小最快。

我认为由于char的排名,在标准的某处陈述了促销行为。

这是我回复的回复:

  

"字符不会默认提升为整数。寄存器大小   是32位,但一行中的多个字节值可以打包成a   单个寄存器作为编译器实现。这并非总是如此   预测。您唯一可以验证自动促销的时间是   当没有包裹时,类型被传递到调用堆栈中   结构因为C标准正式需要32位值   调用堆栈内存。大量的CPU架构已经过优化   程序集调用非32位值,因此不能进行任何假设   关于这种情况下的CPU或编译器。"

我不确定谁是对的,还有什么可以相信的。有什么事实?

4 个答案:

答案 0 :(得分:8)

  

字符会自动提升为C表达式中的整数

是的,他们是。 C99第6.3.1.8节,常用算术转换

  

许多期望算术类型操作数的运算符会导致转换并产生结果   以类似的方式输入类型。目的是确定操作数的通用实数类型   和结果。对于指定的操作数,将转换每个操作数,而不更改类型   域,对应的实类型是常见的实类型。除非   另外明确说明,常见的真实类型也是相应的实际类型   结果,其类型域是操作数的类型域,如果它们是相同的,   否则复杂。这种模式称为通常的算术转换:

     
      
  • 首先,如果任一操作数的相应实数类型是long double,则另一个   操作数在不更改类型域的情况下转换为对应的实类型为long double的类型。
  •   
  • 否则,如果任一操作数的相应实数类型是double,则另一个   操作数在不更改类型域的情况下转换为其类型的类型   相应的真实类型是双倍。
  •   
  • 否则,如果任一操作数的相应实数类型为float,则为另一个   操作数在不更改类型域的情况下转换为其类型的类型   相应的实际类型是float.62)
  •   
  • 否则,将对两个操作数执行整数提升。那么   以下规则适用于提升的操作数:      
        
    • 如果两个操作数具有相同的类型,则不需要进一步转换。
    •   
    • 否则,如果两个操作数都有有符号整数类型或两者都有无符号   整数类型,具有较小整数转换等级类型的操作数是   转换为具有更高等级的操作数的类型。
    •   
    • 否则,如果具有无符号整数类型的操作数的等级大于或等于   等于另一个操作数的类型的等级,然后是操作数   有符号整数类型转换为带有unsigned的操作数的类型   整数类型。
    •   
    • 否则,如果带有符号整数类型的操作数的类型可以表示   那么,带有无符号整数类型的操作数类型的所有值   具有无符号整数类型的操作数将转换为该类型   带有符号整数类型的操作数。
    •   
    • 否则,两个操作数都将转换为无符号整数类型   对应于带有符号整数类型的操作数的类型。
    •   
  •   

整数促销在第6.3.1.1.2节中描述:

  

无论是int还是unsigned,都可以在表达式中使用以下内容   可以使用int:

     
      
  • 具有整数类型的对象或表达式,其整数转换等级小于或等于int和unsigned的等级   中间体
  •   
  • _Bool,int,signed int或unsigned int
  • 类型的位字段   
     

如果int可以表示原始类型的所有值,则值为   转换为int;否则,它将转换为unsigned int。   这些被称为整数促销。所有其他类型都是不变的   通过整数促销。

char的排名小于或等于int的排名,因此此处包含char

(作为脚注,提到整数促销仅作为通常的算术转换,某些参数表达式,一元+-和{{的操作数的一部分应用。 1}},以及移位运算符的两个操作数。)

如评论中所述,还对函数调用参数执行整数提升。

答案 1 :(得分:4)

是的,具有多个char s的表达式,如添加等等。 (但不是逗号运算符之类的东西),以及其他一些东西,都是在提升的值上完成的(提升为int)。见例如。 N3797,§4.5

关于你同事的陈述,其中有许多错误的内容:

  • “注册表”(寄存器)大小通常不是 32位,根本不是。

  • 如果一个字节有8位,当然一个32位的寄存器可以容纳多个字节,
    但这不相关,编译器不是它可能的原因。

  • 这是“预测”怎么样?

  • 关于标准和32位的位完全错误。

  • 整数促销与struct

  • 无关
  • 在标准中,没有“堆叠”。那个概念
    实际使用的堆栈并非强制性(正如其他人所说)。

  • 他说一切都需要32位,但是作为CPU 也可以处理其他尺寸,没有什么可以肯定的吗?现在怎么办?

...

答案 2 :(得分:2)

C不需要堆栈或指定任何有关32位寄存器的内容。

整数促销的理由之一是CERT把它:

  

执行整数提升以避免因中间值溢出而导致的算术错误。例如:

signed char cresult, c1, c2, c3;
c1 = 100;
c2 = 3;
c3 = 4;
cresult = c1 * c2 / c3;

请注意,并非所有运算符都会使其参数成为通常算术转换的主题,例如,对于赋值运算符或强制转换运算符,不存在整数提升。

答案 3 :(得分:0)

逻辑上,是的,所有操作都是在提升的值上执行的。但是,在 as-if 规则下,可以证明结果相同的编译器可以选择省略实际的促销。简单f需要将APP提升为NO_APP,但实际上根本不需要这样做。优化器可以轻松地看到if (ch==0)为零时,ch为零。

因此,实际CPU性能和不同CPU风格的重要性低于您对性能的考虑;它是否优化器能够找到一套合适的指令。