预处理后gcc可以输出C代码吗?


104

我正在使用一个开放源代码库,该库似乎具有很多预处理指令以支持除C之外的多种语言。因此,我可以研究该库的功能,希望看到预处理后要编译的C代码,更像是我写的东西。

gcc(或Linux中通常可用的任何其他工具)可以读取此库,但输出将预处理转换为人类可读性的C代码吗?


预处理的代码将不再具有任何预处理器指令,但我可以肯定,它比预处理之前的可读性要差得多……
Alex W

2
@AlexW-这完全取决于编写代码的人滥用预处理器的程度。
假名称

1
请考虑在此处更改您接受的答案。 gcc -E比必须重新编写行使其更有效cpp
灰色

Answers:


193

是。传递gcc -E选项。这将输出预处理的源代码。


12
如果您的编译器命令已经具有类似的参数-o something.o,则可能还需要将其更改为-o something.i。否则,预处理后的输出将在.o文件中。
Tor Klingberg,2015年

@TorKlingberg我可以一次对多个文件执行此操作吗?
user2808264

@ user2808264gcc -E file1.c file2.c ...
Matthieu

68

cpp 是预处理器。

运行cpp filename.c以输出预处理的代码,或者更好的是,使用将其重定向到文件 cpp filename.c > filename.preprocessed


2
我认为这是最好的答案,因为它直接演示了cpp。Linux系统(至少是Manjaro)似乎也默认具有-E。无论哪种方式,我都可以从该命令获得相同的结果。diff在文件中没有差异。这似乎也是预处理代码以查找宏中的错误的有用方法。好问题,好答案(IALCTHW)。
lee8oi

17

我正在使用gcc作为预处理器(用于html文件。)它确实可以满足您的需求。它扩展“#-”指令,然后输出一个可读文件。(我没有尝试过使用其他C / HTML预处理器来执行此操作-它们将行连接起来,使特殊字符阻塞,等等。)假设您已安装gcc,则命令行为:

gcc -E -xc -P -C -traditional-cpp code_before.cpp> code_after.cpp

(不必是'cpp'。)http://www.cs.tut.fi/~jkorpela/html/cpre.html上对此用法有很好的描述

“ -traditional-cpp”保留空格和制表符。


非常感谢,这对于生成python cffi cdef非常有帮助!
amirouche

13

-save-temps

这是要记住的另一个好选择:

gcc -save-temps -c -o main.o main.c

main.c

#define INC 1

int myfunc(int i) {
    return i + INC;
}

现在,除了正常输出外main.o,当前工作目录还包含以下文件:

  • main.i 是所需的预设文件,其中包含:

    # 1 "main.c"
    # 1 "<built-in>"
    # 1 "<command-line>"
    # 31 "<command-line>"
    # 1 "/usr/include/stdc-predef.h" 1 3 4
    # 32 "<command-line>" 2
    # 1 "main.c"
    
    
    int myfunc(int i) {
        return i + 1;
    }
  • main.s 是一个奖励:-),并包含生成的程序集:

        .file   "main.c"
        .text
        .globl  myfunc
        .type   myfunc, @function
    myfunc:
    .LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    %edi, -4(%rbp)
        movl    -4(%rbp), %eax
        addl    $1, %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
    .LFE0:
        .size   myfunc, .-myfunc
        .ident  "GCC: (Ubuntu 8.3.0-6ubuntu1) 8.3.0"
        .section    .note.GNU-stack,"",@progbits

如果要对大量文件执行此操作,请考虑改用:

 -save-temps=obj

将中间文件保存到与 -o对象输出而不是当前工作目录中,从而避免了潜在的基名冲突。

此选项相对于 -E是可以轻松地将其添加到任何构建脚本中,而不会干扰构建本身。

关于此选项的另一个很酷的事情是,如果您添加-v

gcc -save-temps -c -o main.o -v main.c

它实际上显示了正在使用的显式文件,而不是下的难看的临时文件/tmp,因此很容易确切知道发生了什么,其中包括预处理/编译/组装步骤:

/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu main.c -mtune=generic -march=x86-64 -fpch-preprocess -fstack-protector-strong -Wformat -Wformat-security -o main.i
/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -fpreprocessed main.i -quiet -dumpbase main.c -mtune=generic -march=x86-64 -auxbase-strip main.o -version -fstack-protector-strong -Wformat -Wformat-security -o main.s
as -v --64 -o main.o main.s

在Ubuntu 19.04 amd64,GCC 8.3.0中进行了测试。


1
比-E更优雅,因为我可以将-save-temps添加到CFLAGS,而无需更改构建脚本的整体行为。谢谢!
EvertW '19

这确实非常有用,并且-E对于单个文件非常方便。
Subin Sebastian


1

假设我们有一个名为Message.cpp的文件或一个.c文件

步骤1:预处理(参数-E)

g ++ -E。\ Message.cpp> P1

生成的P1文件具有扩展的宏,头文件的内容以及注释。

步骤2:将预处理的文件转换为程序集(参数-S)。该任务由编译器完成

g ++ -S。\ Message.cpp

生成一个汇编器(ASM)(Message.s)。它具有所有汇编代码。

步骤3:将汇编代码转换为目标代码。注意:Message.s是在Step2中生成的。 g ++ -c。\ Message.s

将生成一个名为Message.o的对象文件。它是二进制形式。

步骤4:链接目标文件。此任务由链接器完成

g ++。\ Message.o -o MessageApp

此处生成一个exe文件MessageApp.exe。

#include <iostream>
using namespace std;

 //This a sample program
  int main()
{
cout << "Hello" << endl;
 cout << PQR(P,K) ;
getchar();
return 0;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.