【问题标题】:How possibly can a unary +/- operator cause integral promotion in "-a" or "+a", 'a' being an arithmetic data type constant/variable?一元 +/- 运算符怎么可能导致“-a”或“+a”中的积分提升,“a”是算术数据类型常量/变量?
【发布时间】:2014-11-15 15:21:26
【问题描述】:

这条看似微不足道的台词摘自我的 Mike Banahan & Brady (Section 2.8.8.2) 的 C 书。

我可以理解隐式提升是如何在 c=a+b 等表达式中发挥作用的,具体取决于操作数的类型,但我无法理解在 -b 之类的表达式中如何以及在何种情况下会出现相同的情况,其中 b 是任何合法的操作数。你能解释一下,然后举个恰当的例子吗?

提取的文本如下:

通常的算术转换适用于两个操作数 运算符的二进制形式。只有积分促销是 对运算符的一元形式的操作数执行。

更新:

为了避免被忽视,我在这里根据 OUAH 在评论中的回答添加我所问的内容—— 书上说'Only the integral promotions are performed'...是不是意味着在x=-y这样的表达式中,'x'是一个long double,'y'是一个float,'y'不会被提升为long double如果我们明确使用一元运算符?我知道会这样,但仍然要求它更清楚地了解“仅整数促销......”部分。

更新:

您能否举例说明提升对以下位运算符的作用?对于最后三个,我是否应该假设每当在变量上使用它们时,它首先被提升为整数类型?前三个“通常的算术转换”到底是什么意思?你能举个小例子吗?如果可以在这里解决,我不想将其作为单独的问题发布。

【问题讨论】:

  • 我认为是因为它被翻译成a * +1a* -1
  • @GradyPlayer: 不,一元 + 和一元 - 是不同的操作数;除了正确实现其行为所需的任何机器代码之外,它们不会被“翻译”成任何东西。

标签: c type-conversion expression integer-promotion


【解决方案1】:

以 32 位系统为例:

 unsigned char a = 42;

 printf("%zu\n", sizeof a);   // prints 1

 printf("%zu\n", sizeof +a);  // prints 4, a has been promoted to int

【讨论】:

  • 这是一个例子,不是解释。
  • @GradyPlayer OP 要求举个例子,就在这里。此外,我认为这个例子不言自明,如果 OP 不清楚,我鼓励他在这个答案中发布更多问题。
  • @ouah 书上说“只执行积分提升”...这是否意味着在像 x=-y 这样的表达式中,其中 'x' 是long double 和 'y' 是浮点数,如果我们明确使用一元运算符,'y' 不会提升为 long double?你能举个例子或理由支持或反对它吗?
  • @Thokchom 整数提升关注整数类型,这里yfloat,因此在-y 中不执行整数提升。在x = -y 中,通常的算术转换是使用= 运算符执行的。也就是说,-y 的值,它是 float 类型的,在分配给 x 之前,会被转换为 long double 类型。
  • @ouah 如果您能回答我刚才在第二次更新中提出的问题,这将对我有很大帮助。我不想把它作为一个单独的问题发布。谢谢。
【解决方案2】:

我不确定,但我认为每个操作都被提升为适当的类型。首先转换完成,然后操作完成。 -b操作改变了result变量的值,所以应该先进行提升,再进行值符号的转换。

+b这样的操作也是一个操作,所以有一个Promotion + Operation的过程。我不知道在这种具体情况下代码优化是否可以跳过这个过程。

【讨论】:

    【解决方案3】:

    在使用二元运算符的操作期间,将算术提升到最需要的形式,从 int 到 long、float 或 double。

    double c=2+3.5
    

    但在一元运算符+,- 中,仅允许整数类型数据类型的提升。从 short 到 int 或 long。

    unsigned char a=255;
    cout<<sizeof(a)<<endl; //prints 1
    cout<<sizeof(+a)<<endl; //prints 4
    cout<<sizeof(++a)<<endl; //prints 1
    

    所以这个 Integral promtions 不适用于其他一元运算符 ++aa++

    【讨论】:

      【解决方案4】:

      对于一元算术运算符,C 标准规定(在第 6.5.3.3 节中)

      对操作数执行整数提升,结果具有提升的类型。

      它还在第 6.3.1.1 节中定义了该术语:

      如果 int 可以表示原始类型的所有值(如 受宽度限制,对于位域),值转换为 一个int;否则,它将被转换为 unsigned int。 这些称为整数促销。所有其他类型都是 整数促销保持不变。

      (参考 2011 C 标准的N1570 draft。)

      我相信这样做的理由是实现不需要支持任何比int(一个“单词”)更窄的类型的算术运算。比int 窄的操作数在对其进行操作之前转换为intunsigned int

      对于二元运算符(采用两个操作数的运算符),还有一个附加要求,即两个操作数必须是同一类型。典型的 CPU 可能有指令将两个 32 位有符号整数相加,或两个 32 位无符号整数,或两个 64 位有符号或无符号整数相加,但没有一个指令会直接相加,例如,一个 32 位有符号整数和一个64 位无符号整数。为此,我们有常用的算术转换,在第 6.3.1.8 节中描述。例如,这些规则告诉您,当您尝试将 int 添加到 double 时会发生什么:通过转换将 int 操作数提升为类型 double,并且添加会添加结果两个 @ 987654333@ 操作数。

      移位运算符不需要通常的算术转换,因为没有特别需要两个操作数属于同一类型。左操作数是要操作的值;右操作数指定要移动的位数。

      这是否意味着在像x=-y 这样的表达式中,其中xlong doubleyfloat,如果我们明确使用y 将不会被提升为long double unary 运算符?

      赋值导致右操作数转换为左操作数的类型。表达式-y 的计算独立于它出现的上下文(对于大多数表达式来说都是如此)。所以一元 - 应用于它的操作数,它是 float 类型的(整数提升不影响它),产生 float 类型的结果。该分配导致 float 值在分配给 x 之前转换为 long double

      您的问题的标题询问这怎么可能发生。我不确定那是什么意思。转换规则在语言标准中指定。编译器遵循这些规则。

      【讨论】:

      • 感谢您花时间提出这么好的答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多