"?:"发生了什么?我不知道返回类型

Bel*_*now 19 c unsigned signed ternary-operator conditional-operator

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

我认为价值(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;
Run Code Online (Sandbox Code Playgroud)

我希望输出是1,但实际输出是0.

Eri*_*hil 20

类型a ? b : c不依赖于a.它的类型b和无条件地决定c.完整规则很复杂,但是,对于算术操作数,类型由通常的算术转换确定.实际上,两个操作数被转换为通用类型.对于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段描述了指针的结果:

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

总之,这说:

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