在布尔值上使用按位取反运算符(~)是否会引发未定义行为?

11
如果一个C++程序将按位非(~)操作符应用于布尔值,这是否会调用未定义的行为?
例如,以下程序是否定义良好?
bool f = false;
bool f2 = ~f;    // is f2 guaranteed to be true, or is this UB?
bool t = true;
bool t2 = ~t;    // is t2 guaranteed to be false, or is this UB?

(是的,我知道存在一个更适合这种情况的!运算符;但是为了本问题的目的,我们将忽略它的存在;))

3
我猜测~在执行任何操作之前会将参数提升为int,因此~0会转换为true。如果没有查看代码,无法百分之百确定。 - chris
@chris,你是对的。 - Carl Norum
“做 bool b = 13; [或类似的事情] 是未定义行为吗?” - Mats Petersson
@MatsPetersson:不,int13 会隐式转换为 bool,得到 true - Keith Thompson
3个回答

8

5.3.1/10 操作数~必须具有整数或未作用域枚举类型;结果是其操作数的补数。执行整形提升。 [我强调]

4.5/6 类型为bool的prvalue可转换为类型为int的prvalue,其中false变为零,true变为一。

4.5/7 这些转换称为整形提升。

因此,~false是一个int,其位模式由全部为1的位组成 - 表示0的位模式的补码,即全部为零(按照3.9.1/7的要求)。同样,~true是一个int,它是1的位表示的补码 - 即所有位都是1,最低有效位为零。这两个值在布尔上下文中将评估为true


@MattMcNabb 这个标准在哪里说了呢?我实际上正在寻找那个措辞,但很遗憾没有找到。在 C99 6.2.6.2 中有类似的措辞 - 或许可以通过引用将这种措辞纳入 C++ 标准中,但这听起来是一个相当薄弱的论点。我是否漏掉了一些显而易见的东西? - Igor Tandetnik
@MattMcNabb 啊,对了。我忘记了“纯二进制计数系统”这个专业术语。让我更新答案。 - Igor Tandetnik
1
我猜有一点争议的空间,负零可以作为“0”的另一种表示形式,在补码中。 - M.M
@MattMcNabb 至少 C99 对如何产生负零有限制(基本上只能通过位操作)。仅写 0(int)false 不应该这样做。但是,是的,C++ 标准没有类似的措辞。 - Igor Tandetnik

3
算术运算符对其操作数执行整数提升。具体来说,[expr.unary.op] / 9也适用于 ~ 运算符。
因此,~t 等同于 ~1。这会产生一个有效的非零整数。
整数转布尔类型的转换由 [conv.bool] 定义:

将零值、空指针值或空成员指针值转换为 false;将任何其他值转换为 true。

因此,bool t2 = ~t; 会产生 t2 == true。没有未定义行为。
~f 等同于 ~0。在二进制补码中,~0 的值为 -1,因此我们会得到 f2 == true在使用一的补码的 C++ 系统中,如果有的话,那么 ~0 的效果是不清楚的。

1
bool t = true;
bool t2 = ~t;    // is t2 guaranteed to be false, or is this UB?

我想这并不是保证的,因为

  bool b = true;
  bool b1 = ~b;
  cout << b1;

输出一个"true"

我想这与布尔表示有关...如果它是一个字节,那么00000001将取反为11111110,这不是零。升级也可能起作用,但是它是同一首曲子。

关键在于它是"按位"而不是"逻辑"。因此,除非布尔表示是单个位,否则不应期望两者匹配。

易于完全定义行为。


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