将按位与的结果赋值给布尔变量:C++

4

我使用g++ 4.1.2编译的C++代码中有以下循环:

while(1) {
    int status = getStatus();
    bool firstOk = status & 0x1;
    bool secondOk = status & 0x2;
    if(firstOk != m_firstOk) {
        logStatus(1, firstOk);
        m_firstOk = firstOk;
    }
    if(secondOk != m_secondOk) {
        logStatus(2, secondOk);
        m_secondOk = secondOk;
    }

    sleep(1);
}

请注意,logStatus()函数通过值传递其参数,因此参数不会被修改。m_firstOk和m_secondOk当然是bool类型的成员属性。

这个函数之前一直工作得很好,但最近我收到了一个报告说它没有检测到firstOk何时发生了变化。我使用gdb附加到运行的进程上,当我看到以下内容时,我感到非常惊讶:

(gdb) p m_firstOk
$1 = true
(gdb) p m_secondOk
$2 = true
(gdb) p firstOk
$3 = 244

什么鬼?当firstOk应该是0x1的按位与结果时,怎么会变成244呢?我知道布尔值实际上是存储为整数,但我的按位与为什么被忽略了呢?由于它是244,它被评估为true,而它应该是false,这就是问题的原因。

把按位与的结果分配给布尔值是安全的吗?这是一个gcc的错误吗?还是我应该像下面这样做?

bool firstOk = (status & 0x1) ? true : false;

感谢您的预先帮助。

听起来像是未定义行为。 - R. Martinho Fernandes
status 应该是无符号的吗? - Pubby
3
您确定在“sleep()”调用期间存在“firstOk”吗?由于它只是一个简单的布尔值,并且不再使用,因此可能已被重用为其他东西。 “logStatus()”显示什么? - Csq
1
你编译时没有进行任何优化吗?你可以尝试打印firstOk的值,以确保Csq所说的不再是事实。 - leemes
Pubby:这没关系。状态的值可以是0、1、2或3。没有其他的。 - Víctor Fernández
显示剩余2条评论
3个回答

2
本地变量firstOksecondOk在到达sleep()调用时不处于“活动”状态,因此即使它们已经分配了堆栈空间,其值很可能(实际上非常可能)不再存储在任何位置。 如果需要调试其中任何一个变量,则需要执行以下操作之一:
  1. 将它们重新声明为static,这将为它们分配持久性存储器。
  2. firstOksecondOk的声明移到外部范围。(注意,这可能不足够,除非将它们移到文件范围。)
  3. firstOksecondOk的值复制到持久变量或存在于外部范围的变量中,并检查它们。
无论如何,在完成调试过程后,都应该恢复上述任何调试措施。 :-)
至于你最后的问题,语句bool firstOk = status & 0x1是完全正确的,其后设置secondOk的语句也是。将一个int赋给bool会将零/非零值强制转换为falsetrue
至于你的实际错误(你在firstOk上错过了某个转换),我没有看到你在这段代码中可能会丢失它的地方。这部分代码看起来很好。你的getStatus()函数是否需要每秒调用多次?还有其他任何东西可以写入m_firstOkm_secondOk吗?由于它们的声明未显示,因此这些变量可能存在于外部范围。

0
唯一可能的方式是:
1)堆栈已被某种方式覆盖。
2)一旦到达sleep行,临时值就不那么重要了,因此编译器不再跟踪它,因此该内存槽可能已被用于其他用途!
如果一开始可以工作,然后后来开始表现不正常,那么很可能不是代码这部分的编译器错误。

2
不,这是错误的。转换整数 => bool 是明确定义的,相应的类型大小是无关紧要的。没有截断发生。而且在分配给 boolif 语句中也是如此,因此这是双重错误。 - Konrad Rudolph

-1

正确的赋值应该是:

bool firstOk = (status & 0x1) == 0x01;

或者一般来说:

bool flag = (value & mask) == mask;

2
好的,1. 这做了不同的事情(测试整个掩码是否存在与测试某些位是否设置),2. 问题似乎是不同的,即 OP 代码中的 “& 0x1” 似乎评估为具有更多位集合的东西。 - leemes
2
我同意这是一种更好的处理标志的方式,并且C++不应该允许隐式整数=>bool转换。但它确实允许,而且代码是良好定义的。 - Konrad Rudolph

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