三目运算符中的指针转换问题

20

我知道三元运算符有一些令人惊讶的限制,但是我有点困惑,为什么这段代码对我来说不能通过编译:

void foo(bool b)
{
    int* ptr =  ((b) ? NULL : NULL);
}

显然这只是展示问题所需的最小信息。错误信息如下:

[BCC32 Error] Unit11.cpp(20): E2034 Cannot convert 'int' to 'int *'

编译器是不完全符合Embarcadero C++Builder 2010的,所以编译器Bug并非不可能发生...

注:为避免混淆我的意图,已修改括号。

注2:我已经有点困惑了,不知道如何构建这个语句,所以在此解释一下:当b、c和d都是复杂表达式时,在类似a = b? c : d的行中会出现一些编译错误。为了缩小范围,我使用NULL替换了cd以检查b是否有问题。在这一点上,一切都变得一团糟。


1
GCC可以处理它:http://www.ideone.com/ddUyR。:( - R. Martinho Fernandes
2
提供一个最小完整的示例程序,加1。 - Robᵩ
如果你的编译器支持C++0x,你可以使用nullptr,但是在大多数实现中,NULL实际上是一个定义为字面整数的宏,即#define NULL 0 - AJG85
Embarcadero 感谢错误报告。您可以在此处记录:http://qc.embarcadero.com/wc/qcmain.aspx - David
@AJG85:鼓舞人心的是,IDE将nullptr突出显示为关键字,但遗憾的是编译器失败了。BCB2010具有一些C++0x的好处,但不是全部。 - Roddy
显示剩余2条评论
3个回答

23

NULL是一个宏,它展开为0(或某个值为0的整型常量表达式,例如(1-1))。它本身并没有特殊之处。

任何值为零的整型常量表达式都可用作空指针常量,这就是为什么int* ptr = 0;是允许的原因。然而,在这里,表达式是b ? 0 : 0;这不是一个整型常量表达式(b不是常量);它的类型是int,无法隐式转换为int*

解决方法是明确指定你需要一个指针类型:

int* const null_int_ptr = 0;
int* ptr = b ? null_int_ptr : null_int_ptr;
例子有点牵强,通常情况下,当使用条件运算符时,至少一个参数实际上是指针类型(例如b?ptr:0);当操作数之一是指针类型时,0会隐式转换为相同的指针类型,因此整个条件表达式的类型是指针类型,而不是int
唯一可能出现这种“问题”的情况是在条件运算符的第二个和第三个操作数都使用空指针常量的情况下,这种情况相当奇怪。

7
C++11 中的 nullptr 怎么样?int* ptr = b ? nullptr : nullptr; 可以吗? - R. Martinho Fernandes
@Martinho:也许吧;我还没有使用过nullptr的机会。 - James McNellis
4
是的,“nullptr”可以通过编译,因为结果类型将是“nullptr_t”。这就是为什么将“nullptr”添加到语言中的原因。请注意,这里的“nullptr”指的是C++中的一个空指针常量。 - Puppy
我认为人们会感到惊讶的是,条件运算符的结果可以与其参数类型不同;我的一位同事曾因此相信这是C++的一个错误。 - Mark Ransom
@James,我已经弄清楚了如何得到NULL:NULL的结构 - 请参见上文。 NULL:x运行良好。谢谢。 - Roddy
显示剩余3条评论

4
您的问题是,在您的系统上,NULL被定义为0,在三元运算符上下文中假定为int。如果您将其中一个操作数static_castint*,它应该自动升级另一个操作数。

但是,为什么首先要使用这样的结构呢?


我曾经使用过类似 a = b ? NULL : c; 的语句。NULL:NULL 只是去掉了多余的上下文,让我感到更加惊讶。 - Roddy
嗯,也许我需要在测试中退回一两步。敬请关注...谢谢。 - Roddy

3

NULL可以被定义为具有int甚至long类型,因此三元运算符具有相同的类型。没有指针类型的隐式转换,因此编译器会生成错误。

这里的问题是,常量整数表达式评估为零(臭名昭著的空指针常量)存在隐式转换。

可能的解决方案是进行显式转换:

int* ptr =  b ? (int*) NULL : NULL;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接