C中的三元运算符

Ton*_*moy 13 c

为什么这个节目是给意外的数字(例如:2040866504,-786655336)?

#include <stdio.h> 
int main()
{
     int test = 0;
     float fvalue = 3.111f;
     printf("%d", test? fvalue : 0);

     return 0;
}
Run Code Online (Sandbox Code Playgroud)

为什么要打印意外的数字而不是0?它应该做隐式的类型转换吗?这个程序用于学习目的并不严重.

Dav*_*rtz 18

最有可能的是,您的平台在浮点寄存器中传递浮点值,在不同寄存器(或堆栈)中传递整数值.你告诉你printf寻找一个整数,所以它在寄存器中查找整数(或在堆栈中).但是你传递了它float,所以零被放置在printf从未看过的浮点寄存器中.

三元运算符遵循语言规则来决定其结果的类型.它有时不能是整数,有时候是浮点数.这些可能是不同的大小,存储在不同的地方,等等,这将导致无法生成合理的代码来处理两种可能的结果类型.

这是猜测.也许正在发生一些完全不同的事情.由于某种原因未定义未定义的行为.如果没有丰富的平台和编译器细节经验和知识,这些事情是无法预测的,也很难理解.永远不要让别人说服UB是好的或安全的,因为它似乎适用于他们的系统.


hac*_*cks 11

因为您%d用于打印float值.使用%f.使用%d打印float值调用未定义的行为.


编辑:关于OP的评论;

为什么打印随机数而不是0?

编译此代码时,编译器应该给出警告:

[Warning] format '%d' expects argument of type 'int', but argument 2 has type 'double' [-Wformat]
Run Code Online (Sandbox Code Playgroud)

此警告是自解释的,这行代码正在调用未定义的行为.这是因为,转换规范%d指定printfint值从二进制转换为十进制数字字符串,而%ffloat值进行相同操作.在传递fvalue编译器时,知道它是float类型的,但另一方面,它看到printf期望一个类型的参数int.在这种情况下,有时它会按照您的预期进行,有时它会达到我的预期.有时它会做到没人想到的(David Schwartz的评论).
参见测试用例12.它工作正常%f.

它应该做隐式的类型转换吗?

没有.

  • @MarkRansom; 为什么?请参阅测试用例[1](http://ideone.com/Ig5uub)和[2](http://ideone.com/woe4XU). (4认同)
  • @Tonmoy:`exp3`的类型不依赖于`exp2`的类型,但表达式的类型整体取决于它们.类似于`3`是类型`int`,`2.0`是类型`double`,但表达式`(3 + 2.0)`的值作为整体是类型`double`.如果表达式的类型根据条件是真还是假而改变,则三元运算符会导致混乱. (4认同)
  • @MarkRansom:绝对重要. (3认同)
  • @MarkRansom:你的"应该"的想法是错误的.即使表示相同,也没有理由按预期工作.由于默认促销,参数是"0.0"(一个"双")而不是"0.0f"(一个"浮动"). (3认同)
  • @Tonmoy"隐式类型转换"是矛盾的,根据定义,类型转换是明确的.也许你在谈论"隐性转换".但即使这样做也没有完成(除了`float`在传递给可变函数时被提升为`double`).`printf()`不是魔法. (2认同)

ste*_*fan 8

虽然现有的upvoted答案是正确的,但我认为它们太过技术性而忽略了初学程序员可能具有的逻辑:

让我们看一下在某些主题中引起混淆的陈述:

printf("%d", test? fvalue : 0);
        ^    ^     ^        ^
        |    |     |        |
        |    |     |        - the value we expect, an integral constant, hooray!
        |    |     - a float value, this won't be printed as the test doesn't evaluate to true 
        |    - an integral value of 0, will evaluate to false
        - We will print an integer!
Run Code Online (Sandbox Code Playgroud)

编译器看到的有点不同.他同意test意义的价值false.他同意使用fvaluea float0整数.但是,他了解到三元运算符的不同可能结果必须是同一类型!intfloat不是.在这种情况下," float胜利" 0变成0.0f!

现在printf不是类型安全的.这意味着您可以错误地说"打印一个整数"并传递一个浮点数,而无需编译器注意.恰好发生了这种情况.无论价值test是多少,编译器推断出结果都是类型的float.因此,您的代码相当于:

float x = 0.0f;
printf("%d", x);
Run Code Online (Sandbox Code Playgroud)

此时,您会遇到未定义的行为.float根本不是integral预期的东西%d.

观察到的行为取决于您正在使用的编译器和机器.你可能会看到跳舞的大象,虽然大多数终端都不支持这种大象.