未初始化bool类型变量使用的潜在问题

if 语句

以下引用自"The C Programming Language 2nd Edition"未初始化bool类型变量使用的潜在问题_第1张图片

从描述中可以概括为:

  • 0为假
  • 非0为真

相信这也是大家(包括我自己在内)习以为常的“真理”。

特别要注意的是,在C语言中,并没有bool类型。

到了C++中,在语言层面已经有bool类型了。上述中“0为假,非0为真”在大多数情况下还是适用的,但是也有例外的情况,使得上述“真理”在某些情况下就不成立了。

出现条件

  • 未初始化的bool类型变量,搭配
  • 逻辑非 !

实验

little endian,x86_64,sizeof(int) = 4

#include 
#include 
#include 

void f1(void *p)
{
    bool *b = (bool *)p;
    if (!*b)
    {
        printf("!bool: true\n");
    }
    else
    {
        printf("!bool: false\n");
    }
}

void f2(void *p)
{
    uint8_t *b = (uint8_t *)p;
    if (!*b)
    {
        printf("!uint8_t: true\n");
    }
    else
    {
        printf("!uint8_t: false\n");
    }
}

int main(int argc, char **argv)
{
    int i = atoi(argv[1]);
    uint8_t *c = (uint8_t *)&i;
    printf("0x%02x ", *c++);
    printf("0x%02x ", *c++);
    printf("0x%02x ", *c++);
    printf("0x%02x\n", *c++);
    f1(&i);
    f2(&i);

    return 0;
}

运行

读取命令行输入的参数,模拟未初始化的内存区域为指定的值。

其中,case1和case2符合我们对于“0为假,非0为真”的认知。

case3中,对于int的打印,也符合这个认知。但是对于bool的打印却出乎意料(因为2为真,!2应该是假)。

case1

./bool 0

0x00 0x00 0x00 0x00

!bool: true

!uint8_t: true

case2

./bool 1

0x01 0x00 0x00 0x00

!bool: false

!uint8_t: false

case3

./bool 2
0x02 0x00 0x00 0x00
!bool: true
!uint8_t: false

解释

对比示例代码中的f1和f2函数生成的汇编代码:

未初始化bool类型变量使用的潜在问题_第2张图片

可以看到,对于bool类型变量的逻辑非操作,有一条xor的汇编指令:

xorl    $1, %eax

该指令只对eax中的最后一个bit进行取反,对于其它bit原样保留。

在case3中,对于输入的数值2,即eax=2,其2进制表示为:

00000010

对最后一个bit取反后为:

00000011

testb   %al, %al

该指令测试al(eax的低8位)是否为0,显然 3 != 0,因此打印“!bool: true”。

总结

  • “0为假,非0为真”并不是绝对的“真理”
  • 在C++中,bool类型一定要初始化

你可能感兴趣的:(numpy,c++)