【问题标题】:What is happening in "? :"? I have no idea about the return type“?:”中发生了什么?我不知道返回类型
【发布时间】:2019-06-01 09:49:16
【问题描述】:

我认为 ((1 ? (int)1 : (unsigned int)2) > -1) 的结果是 1 (true),但实际上它在 Visual Studio 2017 中是 0 (false)。

我认为(1 ? (int)1 : (unsigned int)2) 的值应该是(int)1,因为1 ? 为真,而1 > -1 为真。

不知道这个表达式最终结果为假的原因。

当我尝试像((int)(1 ? (int)1 : (unsigned int)2) > -1) 一样投射时,它会返回1 (true)。

signed int test = -1;
signed int si = 1;
unsigned int ui = 2;

printf("%d\n", ((1 ? si : ui) > test));
return 0;

我希望输出为1,但实际输出为0

【问题讨论】:

  • (WHATEVER ? (int)1 : (double)42) 的类型始终相同。更改WHATEVER 时类型不会更改。见c99 6.5.15
  • @manjy:这不是that 的副本。该问题及其最佳答案涉及二元运算符。首先,? : 不是二元运算符,并且无论其第一个操作数的值如何,最后两个操作数都不会组合在一个操作中。确实,当? : 具有算术操作数时,通常的算术转换适用,但该问题并未说明这一点,因为它没有讨论? : 运算符。 (此外,? : 可能有非算术操作数。)

标签: c ternary-operator unsigned signed conditional-operator


【解决方案1】:

a ? b : c 的类型不依赖于a。它由bc 的类型无条件确定。完整的规则很复杂,但是对于算术操作数,类型由通常的算术转换决定。实际上,这两个操作数被转换为一个通用类型。对于intunsigned int,结果类型为unsigned int

条件运算符 ? : 在 C 2018 标准的第 6.5.15 条中进行了描述。第 4 段说结果“转换为下面描述的类型”。

第 5 段描述了算术类型、结构和联合的结果:

如果第二个和第三个操作数都具有算术类型,则由通常的算术转换确定的结果类型(如果它们应用于这两个操作数)就是结果的类型。如果两个操作数都具有结构或联合类型,则结果具有该类型。如果两个操作数都为 void 类型,则结果为 void 类型。

算术类型是整数和浮点类型,根据 6.2.5 18。(这些包括实数和复数类型。)通常的算术转换在 6.3.1.8 1 中描述,它们是(在我的总结中,未引用):

  • 如果其中任何一个是复数类型,则结果是复数,其余规则描述实部和虚部的类型。否则,结果为真,其余规则描述其类型。
  • 如果任一为long double,则结果为long double
  • 否则,如果任一为double,则结果为double
  • 否则,如果任一为float,则结果为float
  • 否则,整数提升将应用于每个操作数(这些在 6.3.1.1 2 中指定),然后将这两种类型转换为通用整数类型。完整的规则有点复杂,使用需要一些解释的等级概念,并涵盖一些深奥的情况,所以我将仅针对正常情况进行总结:如果两种类型都是int或更窄(意味着更少的位或位数相同但有符号而不是无符号),结果为int。否则,如果两者都是unsigned int 或更窄,则结果为unsigned int。否则,结果是更宽的类型。

结构、联合、void规则很明确:两个操作数必须具有相同的类型,这就是结果。

第 6 段描述了指针的结果:

如果第二个和第三个操作数都是指针,或者一个是空指针常量,另一个是指针,则结果类型是指向一个类型的指针,该类型由两个操作数引用的类型的所有类型限定符限定。此外,如果两个操作数都是指向兼容类型或兼容类型的不同限定版本的指针,则结果类型是指向复合类型的适当限定版本的指针;如果一个操作数是空指针常量,则结果具有另一个操作数的类型;否则,一个操作数是指向 void 的指针或 void 的限定版本,在这种情况下,结果类型是指向 void。

总而言之,就是说:

  • 如果任一操作数有限定符(constvolatilerestrict_Atomic),则在结果类型中包括这些。
  • 如果这两种类型不同但兼容(例如一个未知大小的数组和一个已知大小的数组,都具有相同类型的元素),则将这两种类型结合起来。 (除了数组大小之外,其他组合的可能性包括数组的元素是不同但兼容的类型、带有和不带参数列表的函数,以及函数的参数是不同但兼容的类型。)

【讨论】:

  • 所以,根据你的回答,理解我的代码的结果类型是“unsigned int”是否正确,因为这句话,“如果第二个和第三个操作数都有算术类型,那么由通常的算术转换确定的结果类型,如果它们应用于这两个操作数,就是结果的类型。” ?
  • @BellSnow:是的。
【解决方案2】:

除非您完全了解正在展开的内容(并且您想要这种行为)[checkout here why],否则您不应混合使用有符号和无符号值。在幕后,由于您的表达式中有一个 unsigned 数字,因此 C 将您的大于运算符计算为 unsigned integer >。因此,您的比较不会评估 true,因为“unsigned -1”大于您的 unsigned 1

【讨论】:

  • OP 认为他们没有混合有符号和无符号值。他们认为他们从? : 获得了有符号或无符号值;他们不知道? : 结合了这些类型。
  • 确实如此。我写的是一般意义上的。
  • 您的建议非常合理,应避免在算术表达式中混合有符号和无符号类型,因为规则复杂且有些违反直觉。事实上,拥有unsigned 操作数可能并不总是强制使用unsigned 结果类型:例如((1 ? (long)1 : (unsigned)2) > -1) 可能会在不同平台上产生不同的结果,具体取决于int 和@987654333 类型的各自大小@.
  • @chqrlie 完全正确!这种行为更难出错。
  • @delirium: 调试还是调试,这是个问题...:)
【解决方案3】:

?: 运算符的结果是无符号类型,因为它是 intunsigned(您的第二个和第三个操作数)的 common 类型。结果的“预期”值为1,但其类型为unsigned

其余的与?: 完全无关。这个常见问题的许多答案都有详细描述:Comparison operation on unsigned and signed integers

【讨论】:

    【解决方案4】:

    只是在上面加上一个数字,如果我放弃此代码:

    unsigned x = (unsigned)-1;
    

    在我正在调试的程序中,X 的值为 4294967295 (UINT_MAX),即您的程序“看到”比较是这样的:

    ((1 ? (int)1 : (unsigned int)2) > 4294967296)
    

    (本来可以作为评论输入,但我没有声誉。)

    【讨论】:

    • 这是不正确的,4294967296 的类型为 long long(在通用系统上)。也许你打算在那里写4294967295? (但如果是,请添加u 后缀)
    猜你喜欢
    • 1970-01-01
    • 2012-04-07
    • 1970-01-01
    • 1970-01-01
    • 2015-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多