zoukankan      html  css  js  c++  java
  • bool值一定为0或者1吗

    一、bool值的范围
    根据C++语言中的说明,一个bool值可能的值只有两个,要么是0,要么是1。但是对于一个未初始化的bool值变量,它的取值范围却要丰富多彩的多,它的取值范围应该是可以为任意的一个单字节整数。测试的程序非常简单,大家随便打印一下一个未初始化的bool变量的值就应该可以看到各种各样的初始化值。
    二、测试代码
    [tsecer@Harry boolval]$ cat boolval.cpp 
    int level = 0;

    #include <stdio.h>

    int recursive(bool b_var)
    {
        if (level++ > 1024*20 )
            return 0 ;
        bool b_localvar;这个变量是木有初始化的
        printf("%d ",b_var);
        recursive(b_localvar);

    }
    int main()
    {
        recursive(1);
    }
    [tsecer@Harry boolval]$ g++ boolval.cpp -o 
    a.out            boolval.cpp      boolval.cpp.exe  
    [tsecer@Harry boolval]$ g++ boolval.cpp -o boolval.cpp.exe 
    [tsecer@Harry boolval]$ ./boolval.cpp.exe | more
    1    8    8    8    8    8    8    8    8    8    8    8    88    8    8    8    8    8    8    8    8    8    8    8    88    8    8    8    8    8    8    8    8    8    8    8    88    8    8    8    8    8    8    8    8    8    8    8    88    8    8    8    8    8    8    8    8    8    8    8    88    8    8    8    8    8    8    8    8    8    8    8    88    8    8    8    8    8    8    8    8    8    8    8    88    8    8    8    8    8    8    8    8    8    8    8    8
    这个命令一直输出,输出到最后这个输出结果一直是这个非常吉利的8这个数字。按照正常来说,操作系统给用户第一次映射的物理页面是执行过清零动作的,所以所以也就是说输出的所有结果应该是另一组为0的。我以为这里是乱码,但是在打印了5个物理页面之后,打印的内容依然还是这个8,这就有些诡异的。
    三、这里为什么不是0也不是1
    [tsecer@Harry boolval]$ gdb boolval.cpp.exe 
    GNU gdb (GDB) Fedora (7.0-3.fc12)
    Copyright (C) 2009 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "i686-redhat-linux-gnu".
    For bug reporting instructions, please see:
    <http://www.gnu.org/software/gdb/bugs/>...
    Reading symbols from /home/tsecer/CodeTest/perltest/boolval/boolval.cpp.exe...(no debugging symbols found)...done.
    (gdb) disas recursive
    Dump of assembler code for function _Z9recursiveb:
    0x08048474 <_Z9recursiveb+0>:    push   %ebp
    0x08048475 <_Z9recursiveb+1>:    mov    %esp,%ebp
    0x08048477 <_Z9recursiveb+3>:    sub    $0x38,%esp
    0x0804847a <_Z9recursiveb+6>:    mov    0x8(%ebp),%eax
    0x0804847d <_Z9recursiveb+9>:    mov    %al,-0x1c(%ebp) 传递给recursive的bool值放入一个byte结构中
    0x08048480 <_Z9recursiveb+12>:    mov    0x80497e4,%eax
    0x08048485 <_Z9recursiveb+17>:    cmp    $0x5000,%eax
    0x0804848a <_Z9recursiveb+22>:    setg   %dl
    0x0804848d <_Z9recursiveb+25>:    add    $0x1,%eax
    0x08048490 <_Z9recursiveb+28>:    mov    %eax,0x80497e4
    0x08048495 <_Z9recursiveb+33>:    test   %dl,%dl
    0x08048497 <_Z9recursiveb+35>:    je     0x80484a4 <_Z9recursiveb+48>
    0x08048499 <_Z9recursiveb+37>:    mov    $0x0,%eax
    0x0804849e <_Z9recursiveb+42>:    mov    %eax,%edx
    0x080484a0 <_Z9recursiveb+44>:    mov    %edx,%eax
    0x080484a2 <_Z9recursiveb+46>:    jmp    0x80484c4 <_Z9recursiveb+80>
    0x080484a4 <_Z9recursiveb+48>:    movzbl -0x1c(%ebp),%eax
    0x080484a8 <_Z9recursiveb+52>:    mov    %eax,0x4(%esp)
    0x080484ac <_Z9recursiveb+56>:    movl   $0x80485b4,(%esp)
    0x080484b3 <_Z9recursiveb+63>:    call   0x80483a0 <printf@plt>
    0x080484b8 <_Z9recursiveb+68>:    movzbl -0x9(%ebp),%eax
    0x080484bc <_Z9recursiveb+72>:    mov    %eax,(%esp)
    ---Type <return> to continue, or q <return> to quit---
    0x080484bf <_Z9recursiveb+75>:    call   0x8048474 <_Z9recursiveb>
    0x080484c4 <_Z9recursiveb+80>:    leave  
    0x080484c5 <_Z9recursiveb+81>:    ret    
    End of assembler dump.
    (gdb) 
    从汇编代码中可以看到,其中bool变量是存在一个字节为单位来存储的,汇编代码首先把一个字节放入-0x1c(%ebp)中的,高3字节单位全部清零。所以参数中的字节内容的取值范围是0到255字节的范围都是有可能的。
    四、为什么一直是8而不是0
    我当场拿出纸笔比划了一下,情况可能是这样的:
    秘密在于递归执行recursive函数之前,函数还调用了printf函数,该函数将会提前污染堆栈空间中的内容,而整个8是一个0x80地址的最高的一个字节,大家知道,在通常的桌面系统中,用户态的堆栈空间是从2G开始的,也就是0x80开始的堆栈地址。为了便于分析,我这里使用了静态链接的版本分析:
    0x0804828c <_Z9recursiveb+48>:    movzbl -0x1c(%ebp),%eax
    0x08048290 <_Z9recursiveb+52>:    mov    %eax,0x4(%esp)
    0x08048294 <_Z9recursiveb+56>:    movl   $0x80b006c,(%esp)
    0x0804829b <_Z9recursiveb+63>:    call   0x8054ad0 <printf> 此处call返回值占用一个int
    0x080482a0 <_Z9recursiveb+68>:    movzbl -0x9(%ebp),%eax 这个是发送给子函数的bool值的参数。我们现在分析一下之前调用的printf是如何确定的修改这个值的
    0x080482a4 <_Z9recursiveb+72>:    mov    %eax,(%esp)
    ---Type <return> to continue, or q <return> to quit---
    0x080482a7 <_Z9recursiveb+75>:    call   0x804825c <_Z9recursiveb>
    0x080482ac <_Z9recursiveb+80>:    leave  
    0x080482ad <_Z9recursiveb+81>:    ret    
    printf的代码
    (gdb) x/30i 0x8054ad0
    0x8054ad0 <printf>:    push   %ebp push占用一个int。
    0x8054ad1 <printf+1>:    mov    %esp,%ebp
    0x8054ad3 <printf+3>:    sub    $0xc,%esp最后一个esp指向的int就是将要使用的bool值
    0x8054ad6 <printf+6>:    lea    0xc(%ebp),%eax
    0x8054ad9 <printf+9>:    mov    %eax,0x8(%esp)
    0x8054add <printf+13>:    mov    0x8(%ebp),%eax
    0x8054ae0 <printf+16>:    mov    %eax,0x4(%esp)
    0x8054ae4 <printf+20>:    mov    0x80d3d80,%eax
    0x8054ae9 <printf+25>:    mov    %eax,(%esp)
    0x8054aec <printf+28>:    call   0x8063960 <vfprintf> call在堆栈中占用一个int。我们看到的这个地址就是这里call调用的时候被CPU直接压入堆栈中的vfprintf函数的地址,而它的最高字节为0x08,所以显示的8就是此处的8
    0x8054af1 <printf+33>:    leave  
    0x8054af2 <printf+34>:    ret    
    最后的描述可能比较模糊,因为清楚的描述可能需要画图,那样会非常直观,只是我觉得没有这个必要,有兴趣的同学自己验证一下这个过程。

  • 相关阅读:
    设计一个圆柱体类,计算表面积及体积。建立一个半径为3、高为3.5的圆柱体,输出其表面积及体积
    写一个方法完成如下功能,判断从文本框textbox1输入的一个字符,如果是数字则求该数字的阶乘,如果是小写字条,则转换为大写,大写字符不变,结果在文本框textbox2中显示
    写一方法用来计算1+2+3+...n,其中n作为参数输入,返回值可以由方法名返回,也可以由参数返回
    winform控件记录
    写4个同名方法,实现两个整数、两个实数,一个实数一个整数,一个整数一个实数之间的求和。在主调函数中调用这4个方法计算相关的值。(方法的重载)
    写一方法计算实现任意个整数之和.在主调函数中调用该函数,实现任意个数之和。(使用params参数)
    在主函数中提示用户输入用户名和密码。另写一方法来判断用户输入是否正确。该方法分别返回一个bool类型的登录结果和和一个string类型的登录信息。如登录成功,返回true及“登录成功”,若登录失败则返回false及“用户名错误”或“密码错误”(使用out参数)
    Linux下使用Kickstart自动化安装平台架构
    Day10 多线程理论 开启线程
    关闭ipv6的方法
  • 原文地址:https://www.cnblogs.com/tsecer/p/10487397.html
Copyright © 2011-2022 走看看