代码之家  ›  专栏  ›  技术社区  ›  Leedehai

C++:汇编代码包含断言结果

  •  2
  • Leedehai  · 技术社区  · 7 年前

    #include <cassert>
    
    int main() {
        assert(true==false); // A
        assert(true==true);  // B
    }
    

    这是汇编代码( link

    .LC0:
    .string "/tmp/compiler-explorer-compiler11778-61-1sgmkbd.5d1m6g8pvi/example.cpp"
    .LC1:
      .string "true==false"
    main:
      push rbp
      mov rbp, rsp
      mov ecx, OFFSET FLAT:main::__PRETTY_FUNCTION__
      mov edx, 5
      mov esi, OFFSET FLAT:.LC0
      mov edi, OFFSET FLAT:.LC1
      call __assert_fail
    main::__PRETTY_FUNCTION__:
      .string "int main()"
    

    线 A ,它应该触发断言失败,反映在汇编代码中,但 B 不是。

    我的问题是:既然宏观 assert()

    编译器:gcc 7.1,优化 -O0

    编辑 :现在可以在编译时计算assert(),它似乎与static_assert()重叠。。

    1 回复  |  直到 7 年前
        1
  •  4
  •   Daniel H    7 年前

    看起来您正在使用GCC和GNU C库,因此假设 NDEBUG 未定义,则 assert 宏的定义可能如下:

    # define assert(expr)                                                   \
      ((expr)                                                               \
       ? __ASSERT_VOID_CAST (0)                                             \
       : __assert_fail (__STRING(expr), __FILE__, __LINE__, __ASSERT_FUNCTION))
    

    /usr/include/assert.h )

    替换这个(以及它所依赖的所有宏)*可以得到如下结果

    int main() {
    
      ((true == false)
           ? static_cast<void>(0)
           : __assert_fail("true==false", "assert.cpp", 4, "int main()"));
    
      ((true == true)
           ? static_cast<void>(0)
           : __assert_fail("true==true", "assert.cpp", 5, "int main()"));
    }
    

    -O0 ,编译器足够聪明,可以看到这一点 true == true 而不是 true == false __assert_fail "true == true" 也不用费心把它包括在内。

    here 我修改了你的代码,添加了一个必须在运行时进行的检查:

    #include <cassert>
    
    bool check_collatz_conjecture();
    
    int main() {
        // assert(check_collatz_conjecture());
        assert(true==false);
        assert(true==true);
        assert(check_collatz_conjecture());
    }
    

    __assert\u失败 声明为 __attribute__((__noreturn__)) ,编译器知道它不需要担心函数的其余部分,并且它不包括 "check_collatz_conjecture()" 一串如果您取消注释第一个断言,它将同时包含该和 "true == false" 但是,因为它不知道Collatz猜想是否为真(公平地说,目前没有数学家知道)。

    g++ -E assert.cpp -o assert.ii 获取预处理的代码,然后运行 cat assert.ii | sed '/^#/d' 删除文件名和行号的标记,并将代码重新格式化为可读性更强的代码,然后手动替换 __PRETTY_FUNCTION__ "int main()"