【问题标题】:Ternary operator. Automatically types conversion in condition三元运算符。在条件下自动类型转换
【发布时间】:2012-11-08 07:51:51
【问题描述】:

如果我在三元运算符条件下只使用unsigned 类型,这些unsigned 变量会自动转换为signed 类型吗?

简单示例:

unsigned int prevTickSeconds = 48;
unsigned int currentTickSeconds = 5; 

unsigned int secondsLeft = (currentTickSeconds - prevTickSeconds ) ?
                            currentTickSeconds - prevTickSeconds :
                            60 - prevTickSeconds + currentTickSeconds;  

(currentTickSeconds > prevTickSeconds) 如本例所示时,此构造是否可以正常工作?三元运算符中的条件是否会自动进行类型转换?

【问题讨论】:

    标签: c ternary-operator


    【解决方案1】:

    不,没有这样的转换,因为所有类型都是unsigned int,并且会有“下溢”。

    注意:

    60 - prevTickSeconds + currentTickSeconds
    

    当且仅当currentTickSeconds - prevTickSeconds0 时才会执行。

    【讨论】:

      【解决方案2】:

      要让事情按您希望的方式进行,您需要明确告诉编译器它应该处理 singns,如下所示:

      unsigned int prevTickSeconds = 48U;
      unsigned int currentTickSeconds = 5U; 
      
      unsigned int secondsLeft = (((int) currentTickSeconds - (int) prevTickSeconds) > 0)
          ? currentTickSeconds - prevTickSeconds 
          : 60 - prevTickSeconds + currentTickSeconds;  
      

      或者,为了更高效,您可能希望引入一个中间 signed 值:

      unsigned int prevTickSeconds = 48U;
      unsigned int currentTickSeconds = 5U; 
      unsigned int secondsLeft = 0U;
      
      {
        signed int deltaSeconds = currentTickSeconds;
        deltaSeconds -= prevTickSeconds;
      
        secondsLeft = (deltaSeconds > 0)
            ? deltaSeconds  
            : 60 - deltaSeconds;  
      }
      

      【讨论】:

      • 我会投到long,以防万一(避免潜在的溢出)
      • 我建议将其清楚更好地更改为(currentTickSeconds > prevTickSeconds)。感谢您的回答,但我的问题是关于三元算子锻炼。
      【解决方案3】:

      C 不关心你的算法,也不知道你的变量是否会下溢,也不知道下溢是有意的还是意外的。无符号整数的下溢/上溢是明确定义的行为,因此在这种情况下,编译器会很乐意按照您的指示去做:创建下溢。


      一些细节:

      unsigned int secondsLeft =  (currentTickSeconds - prevTickSeconds ) ?
                                  currentTickSeconds - prevTickSeconds :
                                  60 - prevTickSeconds + currentTickSeconds;  
      

      如果我们用它们对应的类型替换这个表达式中的所有变量,我们得到:

      unsigned int = (unsigned int - unsigned int) ?
                      unsigned int - unsigned int :              
                      int - unsigned int + unsigned int;
      

      所有 C 关心的是它的隐式类型提升规则。此表达式中有两条这样的规则:常规平衡(通常的算术转换)和一个用于 ?: 运算符的特殊平衡规则。

      平衡规则规定,如果两个相同大小的整数是表达式的操作数,其中一个是无符号的,则有符号的操作数将被转换为无符号的。

      unsigned int = (unsigned int - unsigned int) ?     // no conversion needed
                      unsigned int - unsigned int :      // no conversion needed
                      (int - unsigned int)               // convert the int to unsigned int
                       + unsigned int;  // we get unsigned + unsigned, no conversion needed
      

      然后将结果存储在一个无符号整数中。

      然而,C 中有一个特殊的(奇怪的)规则,与条件运算符 ?: 相关。第二个操作数和第三个操作数是平衡的,就好像它们是同一表达式的运算符一样。所以如果你有这种情况:

      1 ? (signed int)x : (unsigned int)y;
      

      那么结果将永远是无符号整数。这是因为 x 和 y 被视为同一操作的一部分,即使 y 从未在代码中使用。这可能会产生微妙的错误,在我看来,完全避免使用 ?: 运算符就足够了。

      【讨论】:

      • 三元运算符"weird"的规则到底有什么特别之处呢?您有一个操作,其类型是其操作数的转换(或“平衡”)类型(好吧,它的特殊之处在于第一个操作数的类型被忽略了)。不要将三元运算符误认为if。这是一个表达式,需要一个类型。使用所选操作数的类型是不可能的,因为直到运行时才知道它,无论您是否可以构造一个特殊情况,它可以在编译时就知道。
      • @ChristianRau 因为 C 程序员使用 ?: 作为 if 语句的替代品。但如图所示,就类型提升而言,它的行为不像 if 语句。 if(){} 的内容和 else{} 的内容之间从来没有依赖关系。无论如何,?: 是语言的一个多余特征,它的存在只是为了满足各种模糊的、主观的编码风格意见。被误导的程序员倾向于将它用于“优化”,但与 if 语句相比,它永远不会产生更快的代码。相反,由于强制平衡规则,代码通常会变慢。
      • 好吧,当然使用您(不是您,“C 程序员” 提到您的评论)不完全理解的语言功能可能会导致问题。这并不会使该功能成为一个糟糕的功能。当然这完全是为了方便和清晰(是的,单行条件赋值更简洁并且更清晰),但我也不想一直写i = i + 1,不管它是不是与++i 完全相同。它不是针对运行时优化,而是针对编程、阅读和思考时间的优化。谁认为不同,嗯,确实是被误导了,但这不是 C 的问题。
      猜你喜欢
      • 1970-01-01
      • 2017-08-26
      • 2012-01-22
      • 2012-12-15
      • 1970-01-01
      • 2012-02-12
      • 2019-10-08
      相关资源
      最近更新 更多