【问题标题】:c - how logical expression 2 > -3 calculate in gccc - 逻辑表达式 2 > -3 如何在 gcc 中计算
【发布时间】:2015-10-27 11:41:56
【问题描述】:

假设我有这个文件:

[xiaobai@xiaobai done_read]$ cat my_bool.c 
#include <stdio.h>
int
main() {
        if (2 > -3) {
                printf("true\n" );
        }
        else  {
                printf("false\n" );
        }
}

[xiaobai@xiaobai done_read]$

使用 gdb 编译和调试:

[xiaobai@xiaobai done_read]$ gcc -g3 my_bool.c     
[xiaobai@xiaobai done_read]$ gdb ./a.out
GNU gdb (GDB) Fedora 7.8.2-39.fc21
...
Reading symbols from ./a.out...done.
(gdb) b *main+1
+b *main+1
Breakpoint 1 at 0x400537: file my_bool.c, line 3.
(gdb) r
+r
Starting program: .../a.out 

Breakpoint 1, 0x0000000000400537 in main () at my_bool.c:3
3       main() {
(gdb) s
+s
5                       printf("true\n" );
(gdb) s
+s
_IO_puts (str=0x4005e0 "true") at ioputs.c:34
34      {
(gdb)

它总是跳过if (2 &gt; -3) 构造并进入printf("true\n" );

我想了解如果 2 > -3 在二进制级别中 c 的行为,它如何知道 0x2 大于 0xfffffffffffffffd 而 0xfffffffffffffffd 显然大于 0x2。可能是存储有符号位或其他东西,但它需要在我的系统中检查 long long 最大大小(0x7fffffffffffffff)才能知道 0xffffffffffffffd 有符号位?

似乎 gdb 无法做到这一点,那么我该如何在汇编/二进制级别调试这种逻辑表达式(if 2 &gt; -3)?

[UPDATE] 下面是我在 Fedora 21 中安装的 gcc 配置选项。

[xiaobai@xiaobai note]$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.9.2/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.9.2-20150212/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.9.2-20150212/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
Thread model: posix
gcc version 4.9.2 20150212 (Red Hat 4.9.2-6) (GCC) 
[xiaobai@xiaobai note]$

[UPDATE2] 我更改了标题,因为gdb gcc 是我能想到的唯一调试方法。但理解2 &gt; -3 在 gcc 的 fold-constants.c 或其他源文件中的表现并没有太大帮助。在这种特殊情况下,逻辑操作如何执行/涉及? gcc 在执行逻辑操作之前如何检测符号位?

【问题讨论】:

  • 编译器知道 2 将始终大于-3,因此它可以完全优化整个条件(和另一个分支)。尝试使用-O0 标志编译,它告诉GCC 根本不优化,我不知道它是否会停止那个简单表达式的constant folding
  • 我做了-O0,但这是gcc手册中描述的默认选项,仍然相同。
  • 至于0x00000002如何大于0xfffffffd,阅读了解two's complement
  • 经过一番搜索,似乎GCC中无法禁用常量折叠,所以只要你使用文字值,你就很不走运。尝试声明和使用变量,可能标记为volatile
  • 启用编译器警告并注意它们! gcc 应该已经抱怨 else 路径不可访问。

标签: c debugging gcc gdb logical-operators


【解决方案1】:

我认为实际的问题是“我想了解如果 2 > -3 在二进制级别中 c 的行为”。要找出这一点,您可以观察编译器创建的机器代码。

根据http://www.delorie.com/djgpp/v2faq/faq8_20.html,以下命令应该以人类可读的形式创建汇编代码:

gcc -S foo.c

要了解 CPU 在二进制级别如何处理每个汇编命令,您应该阅读 CPU 手册。

【讨论】:

  • 但问题是 gcc 在转换为汇编代码之前折叠表达式,产生movl $.LC0, %edi 其中.LC0:.string "true"。我认为理解的唯一方法是gdb gcc 进入 gcc 的 fold-const.c 的 `if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) != INTEGER_CST) 部分。这对我来说太难了。我只是希望有人编译器专家可以简要介绍一下这种特殊情况。 gcc 会根据当前系统的最大大小检测符号位吗?两个补码如何计算(不仅仅是常见的理论,还有 gcc 的性能)?涉及哪些逻辑操作?
  • 据我了解,gcc 应该在没有优化的情况下创建两个有符号整数的比较。汇编代码会将这两个整数保存到寄存器中,并进行比较。比较将使用 jg 命令完成,该命令在 CPU 级别执行有符号比较。因此,您的问题与 gcc 或调试无关。它是关于如何在 CPU 级别处理有符号整数的比较。我无法回答。您可能应该提出一个新问题,在其中明确定义您想知道的内容,
【解决方案2】:

因为(2 &gt; -3) 是一个常量表达式,gdb 将其优化掉。如果您改用变量,则不会发生这种情况:

#include <stdio.h>
int main() {
    int i=2, j=-3;
    if (i > j) {
            printf("true\n" );
    }
    else  {
            printf("false\n" );
    }
    return 0;
}

gdb 输出:

[dbush] gdb /tmp/x1
GNU gdb (GDB) Red Hat Enterprise Linux (7.0.1-45.el5)
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 "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /tmp/x1...done.
(gdb) start
Temporary breakpoint 1 at 0x4004a0: file /tmp/x1.c, line 4.
Starting program: /tmp/x1
warning: no loadable sections found in added symbol-file system-supplied DSO at 0x2aaaaaaab000

Temporary breakpoint 1, main () at /tmp/x1.c:4
4           int i=2, j=-3;
(gdb) step
5               if (i > j) {
(gdb)
6                       printf("true\n" );
(gdb)
true
11      }
(gdb)

编辑:

关于(i &gt; j) 的评估方式,有符号整数比较与无符号整数比较的完成方式不同。来自Wikipedia

比较通常使用虚拟减法来实现,其中 检查计算机状态寄存器中的标志,但主要 结果被忽略。零标志指示两个值是否比较 平等的。如果符号和溢出标志的异或为 1,则 减法结果小于零,否则结果为零 或更大。这些检查通常在计算机中实施 条件分支指令。

无符号二进制数可以通过简单的字典排序 排序,其中位值 0 定义为小于位值 1.对于二进制补码值,最高位的意义取反(即1小于0)。

【讨论】:

  • 很抱歉给您带来不便,但我刚刚更新了我的问题。 i > j 如何在 gcc 内部计算?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-26
  • 1970-01-01
相关资源
最近更新 更多