以下代码给出了编译器警告
warning C4133: ':' : incompatible types - from 'YTYPE *' to 'XTYPE *'
但是,这个表达对我来说似乎没问题。有任何想法吗?
struct XTYPE {
int x;
long y;
};
struct YTYPE {
long y;
int x;
};
extern void *getSomething(void);
void Test(void)
{
int b= 0;
struct XTYPE *pX;
struct YTYPE *pY;
void * (*pfFoo)(void);
pfFoo= getSomething;
if (b ? (pX= (*pfFoo)()) // error
: (pY= (*pfFoo)()) )
{
;
}
if (b ? ((pX= (*pfFoo)())!=0) // no error
: ((pY= (*pfFoo)())!=0) )
{
;
}
}
简单来说,这是违反约束的行为。首先,赋值表达式的类型由左侧确定。所以你的案子看到struct XTYPE*
和struct YTYPE*
。
6.5.16 Assignment operators - p3
赋值运算符将值存储在左操作数指定的对象中。赋值表达式在赋值后具有左操作数的值,111)但不是左值。赋值表达式的类型是左值操作数在左值转换后将具有的类型。在左右操作数的值计算之后,对更新左操作数的存储值的副作用进行排序。对操作数的评估是不确定的。
并且条件表达式的操作数类型必须满足此约束:
6.5.15 Conditional operator - p3
下列之一应适用于第二和第三操作数:
- 两个操作数都有算术类型;
- 两个操作数具有相同的结构或联合类型;
- 两个操作数都有空白类型;
- 两个操作数都是指向兼容类型的限定或非限定版本的指针;
- 一个操作数是指针,另一个是空指针常量;要么
- 一个操作数是指向对象类型的指针,另一个是指向合格或非限定版本的void的指针。
由于struct XTYPE*
和struct YTYPE*
不是兼容类型的指针(唯一可能适用的子弹),并且实际上只是指向不相关类型的指针,因此您的程序是不正确的。
这里争论的一个主要问题是MSVC不是一个符合C的编译器(无论如何不是C11)。但是自从MSVC支持的最后一个C版本以来,上述规则没有太大变化,所以你有它。
虽然您没有使用它,但编译器必须通过查看两个RHS路径为第三个操作的结果制作一个合理的类型。在第一种情况下,你给了它2个不相关的指针类型X和Y,它拒绝直接解析为if语句的bool。 (bool在C中不作为特定类型存在,因此需要使用一些int类型)
在第二种情况下,通过与0 / NULL / nullptr进行比较,你已经将此强制转换为bool,尽管你已经将逻辑从if set
切换到if clear
。
在c ++中,我们有继承和相关类型的概念,因此编译器通常可以找到一个通用类型来解析这些类型的语句。根据我的经验,不同的编译器对这种情况的处理方式不同,但是对于严格的合规设置,它应该总是失败,除非其中一个操作数是另一个操作数的子类型。
我过去用来解决这些问题的一种方法是使用“双重打击”!!作为布尔保持原始意义的强制转换:
if (b ? !!(pX= (*pfFoo)())
: !!(pY= (*pfFoo)()) )
{
;
}
双重点的一点是,它可以作为一个具有明确意图的单个操作读取,而其他任何东西都必须由读取器解码。