++和--运算符的布尔值重载

108

今天在编写一些Visual C++代码时,我遇到了一些令人惊讶的事情。似乎C++支持对bool类型使用++(增量),但不支持--(减量)。这只是一个随机决定,还是背后有一些原因?

以下代码可以编译通过:

static HMODULE hMod = NULL;
static bool once = false;
if (!once++)
    hMod = LoadLibrary("xxx");

这个不行:

static HMODULE hMod = NULL;
static bool once = true;
if (once--)
    hMod = LoadLibrary("xxx");

2
嗯,Xcode 和 GCC 编译器也是一样的。 - Vladimir
是的,++onceonce++ 可以在gcc中使用,但是递减操作不能。 - Justin Ardini
也许应该重新标记为“历史”,而不是“操作符-关键字”,这样就可以将其与所有其他有趣的解释分组,说明如果考虑历史,各种疯狂的事情都是合理的? :) - Jon Hanna
注意,自C++17起,bool类型的前置递增运算符已被弃用。来源 - cogle
1
如果您想要使用非弃用的内容,可以将此内容替换为std::exchange(once,false)(注意:不是原子操作)。 - golvok
4个回答

97

这来自于使用整数值作为布尔值的历史。

如果x是一个int,但我按照 if(x)... 将其用作布尔值,那么递增将意味着无论操作之前它的真值如何,操作后它的真值都将为true(除非溢出)。

然而,仅凭对x的真值的了解,不可能预测--的结果,因为它可能导致false(如果积分值为1),或者true(如果积分值为其他任何值-特别是包括0[false]和2或更多[true])。

因此,++有效,而--无效。

++允许在布尔变量上使用以保持兼容性,但其在标准中已被弃用,并已在C ++17中删除。


这假设我x用作布尔值,这意味着直到我完成足够次数的++才会发生溢出。即使使用字符作为类型并且CHAR_BITS低至5,这也要进行32次操作才会不再起作用(这仍然足以证明这是一种糟糕的做法,我不是在为这种做法辩护,只是解释为什么它有效)。对于32位的int,我们当然需要使用++ 2 ^ 32次才会成为问题。但如果我们从一个刚好低于0的值开始,情况就不同了。实际上,在这种情况下,我们可能希望++最终导致false值,例如:

int x = -5;
while(++x)
  doSomething(x);

然而,这个例子把x作为一个int来处理,除了条件判断外。因此,它等同于:

int x = -5;
while(++x != 0)
  doSomething(x);

这与仅使用x作为布尔值不同。


1
谢谢。很高兴知道我仍然可以给人们提供他们喜欢的答案,考虑到我已经很久没有写过一行C++了 :) - Jon Hanna
8
如果x的值为-1(在某些平台上,如VB中),++x 将会是FALSE。 - James Curran
4
在C和C++中,我所想到的情况就是我说“除了溢出”的情况。实际上,在VB中,任何非零的值都有真值TRUE(与C类似),但是它们将 -1 而不是 1 作为true布尔运算的结果,那么NOT(TRUE)为FALSE,NOT(FALSE)为TRUE,x OR TRUE为TRUE,x OR FALSE为x,x AND FALSE为FALSE,x AND TRUE为x,等等,使用相同的运算符进行布尔和位运算(因为VB假定采用二进制补码表示法,-1是所有位都是1)。然而,如果编程人员没有注意到2(true)AND 4(true)的结果是0(false),这可能会在VB中导致一些奇怪的错误。 - Jon Hanna
2
@JonHanna: ANSI C89是第一个C标准。 ANSI C委员会发明了<limits.h>头文件和CHAR_BIT宏。 在此之前,我认为理论上可能存在char比8位窄的实现,但据我所知没有这种情况。 特别地,K&R1(于1978年出版)列出了4个示例实现,所有这些实现都具有8位或9位的char - Keith Thompson
1
@JonHanna:符合标准的 C 语言实现 必须 满足 CHAR_BIT >= 8。标准不允许在这种情况下进行特殊处理。(当然,你可以使用不符合标准的实现方式。) - Keith Thompson
显示剩余9条评论

29

ANSI ISO IEC 14882 2003 (c++03):

5.2.6-2

后缀 -- 操作数的行为类似于后缀 ++ 运算符,但操作数不得为 bool 类型。[注:有关前缀递增和递减,请参见 5.3.2。]

并且毫不意外地...

5.3.2-2

前缀 -- 的操作数通过减去1进行修改。操作数不得为 bool 类型。 前缀 -- 的操作数要求和其结果的属性与前缀 ++ 相同。[注:有关后缀递增和递减,请参见 5.2.6。]

此外,5.6.2-1 和 5.3.2-1 提到 ++ 对于 bool 类型应该为 true,Annex D-1 表示对 bool 类型进行 ++ 是不推荐的。


3
@BlueRaja:请参考Jon Hanna的回答。 - Justin Ardini

11

由于历史原因,这种用法得到了支持。但请注意... 使用bool类型的操作数与++运算符一起使用是已被弃用的,请参阅C++标准(n3092)中的第5.3.2节。

5.3.2 前缀递增和递减[expr.pre.incr]

  • 前缀 ++ 的操作数通过加1进行修改,或者如果它是bool,则设置为true(此用法已被弃用)。操作数必须是可修改的左值。操作数的类型必须是算术类型或指向完全定义的对象类型的指针。结果是更新后的操作数;它是一个左值,如果操作数是位字段,则是一个位字段。如果 x 不是 bool 类型,则表达式 ++x 相当于 x+=1 [注意:请参阅加法(5.7)和赋值运算符(5.17)的讨论,以获取有关转换的信息。—end note]
  • 前缀 -- 的操作数通过减1进行修改。操作数不得为bool类型。前缀--的操作数要求和其结果的属性与前缀++相同。

3
  • 在老的标准(C++98)中,这不是一个错误。
  • 从新的标准开始,递增布尔值已经被弃用。(C++11)
  • 你可以在C++17之前使用布尔值递增。

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