加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

怎么看降低c

发布时间:2020-12-16 05:04:09 所属栏目:百科 来源:网络整理
导读:我正在努力提高对C实际工作原理的理解.有没有办法看看编译器如何将我的代码降低为更简单的代码?例如,我想看看如何调用所有复制构造函数,如何解决重载函数调用,所有模板扩展和实例化完成等等.现在我正在学习C编译器如何通过实验解释我的代码但是,只要看到我
我正在努力提高对C实际工作原理的理解.有没有办法看看编译器如何将我的代码降低为更简单的代码?例如,我想看看如何调用所有复制构造函数,如何解决重载函数调用,所有模板扩展和实例化完成等等.现在我正在学习C编译器如何通过实验解释我的代码但是,只要看到我的代码降低形式就好了,即使它非常难看.我正在寻找类似于g -E的东西,它显示了预处理器的结果,但是对于C来说.

编辑:我应该补充一点,我不是在寻找一个反汇编程序. C源代码和汇编代码之间存在巨大差距.在这个鸿沟内部是复杂的事情,比如模板元编程和对运算符方法的各种隐式调用(赋值!强制转换!构造函数!…)以及具有非常复杂的分辨率规则的重载函数等等.我正在寻找工具,以帮助我理解C编译器如何解释我的代码.现在,我唯一能做的就是尝试一些实验,然后逐步了解编译器正在做什么.我想看看有关正在发生的事情的更多细节.例如,在调试模板元编程问题时,这将有很大帮助.

解决方法

目前,我认为你最好的选择是Clang(你可以在 Try Out LLVM页面上尝试一些简单的代码).

使用Clang / LLVM编译C,C或Obj-C时,您可以要求编译器发出中间表示(LLVM IR),而不是完全采用汇编/二进制形式.

LLVM IR是编译器内部使用的完整指定语言:

> CLang将C代码降低到LLVM IR
> LLVM优化IR
> LLVM后端(例如x86)从IR生成程序集

IR是机器特定代码之前的最后一步,因此您不必学习特定的汇编指令,而且您仍然可以非常低级地表示真正发生的事情.

您可以在优化之前和之后获得IR,后者更能代表实际代码,但远离您最初编写的内容.

C程序示例:

#include <stdio.h>
#include <stdlib.h>

static int factorial(int X) {
  if (X == 0) return 1;
  return X*factorial(X-1);
}

int main(int argc,char **argv) {
  printf("%dn",factorial(atoi(argv[1])));
}

相应的IR:

; ModuleID = '/tmp/webcompile/_10956_0.bc'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-unknown-linux-gnu"

@.str = private unnamed_addr constant [4 x i8] c"%dA0"

define i32 @main(i32 %argc,i8** nocapture %argv) nounwind {
; <label>:0
  %1 = getelementptr inbounds i8** %argv,i64 1
  %2 = load i8** %1,align 8,!tbaa !0
  %3 = tail call i64 @strtol(i8* nocapture %2,i8** null,i32 10) nounwind
  %4 = trunc i64 %3 to i32
  %5 = icmp eq i32 %4,0
  br i1 %5,label %factorial.exit,label %tailrecurse.i

tailrecurse.i:                                    ; preds = %tailrecurse.i,%0
  %indvar.i = phi i32 [ %indvar.next.i,%tailrecurse.i ],[ 0,%0 ]
  %accumulator.tr1.i = phi i32 [ %6,[ 1,%0 ]
  %X.tr2.i = sub i32 %4,%indvar.i
  %6 = mul nsw i32 %X.tr2.i,%accumulator.tr1.i
  %indvar.next.i = add i32 %indvar.i,1
  %exitcond = icmp eq i32 %indvar.next.i,%4
  br i1 %exitcond,label %tailrecurse.i

factorial.exit:                                   ; preds = %tailrecurse.i,%0
  %accumulator.tr.lcssa.i = phi i32 [ 1,%0 ],[ %6,%tailrecurse.i ]
  %7 = tail call i32 (i8*,...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str,i64 0,i64 0),i32 %accumulator.tr.lcssa.i) nounwind
  ret i32 0
}

declare i32 @printf(i8* nocapture,...) nounwind

declare i64 @strtol(i8*,i8** nocapture,i32) nounwind

!0 = metadata !{metadata !"any pointer",metadata !1}
!1 = metadata !{metadata !"omnipotent char",metadata !2}
!2 = metadata !{metadata !"Simple C/C++ TBAA",null}

我个人发现它相对可读(一旦你超越了语言的原始发现,它试图保留变量名,有些,函数名仍然存在).

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读