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

LGT*_*der 90 c preprocessor c-preprocessor preprocessor-directive

我正在使用一个开源库,它似乎有很多预处理指令来支持除C之外的许多语言.这样我就可以研究库正在做什么了我想看看我在预处理后编译的C代码,更像是我写的东西.

gcc(或Linux中常用的任何其他工具)可以读取这个库,但输出的C代码将预处理转换为任何东西并且人类也可以读取吗?

mip*_*adi 182

是.通过gcc -E选项.这将输出预处理的源代码.

  • 如果您的编译器命令已经有一个像`-o something.o`这样的参数,您可能还想将其更改为`-o something.i`.否则预处理的输出将在`.o`文件中. (12认同)
  • 预处理器是否可以选择仅扩展“#define SIZE 1000”或“#ifdef Something #endif”等宏,但不扩展“#include <other_file.h>” 我想查看一个预处理文件,但没有导入外部函数一个文件。 (6认同)

tpd*_*pdi 63

cpp 是预处理器.

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

  • @lee8oi 我很好奇 IALCTHW 是什么意思,但我尝试网络搜索它只得到了这个页面作为搜索结果。这个缩写是什么意思?我很好奇。 (3认同)
  • 我认为这是最好的答案,因为它直接演示了cpp.Linux系统(至少Manjaro)似乎也默认使用-E.无论哪种方式,我从这个命令得到相同的结果.`diff`在文件中没有区别.这看起来像是预处理代码以查找宏中的错误的有用方法.很棒的问题和一个很好的答案(IALCTHW). (2认同)

Jac*_*ter 14

我正在使用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"保留空格和制表符.


Cir*_*四事件 7

-save-temps

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

gcc -save-temps -c -o main.o main.c
Run Code Online (Sandbox Code Playgroud)

main.c

#define INC 1

int myfunc(int i) {
    return i + INC;
}
Run Code Online (Sandbox Code Playgroud)

现在,除了正常输出外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;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 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
    
    Run Code Online (Sandbox Code Playgroud)

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

 -save-temps=obj
Run Code Online (Sandbox Code Playgroud)

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

该选项的优点-E是可以轻松地将其添加到任何构建脚本中,而不会干扰构建本身。

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

gcc -save-temps -c -o main.o -v main.c
Run Code Online (Sandbox Code Playgroud)

它实际上显示了下方的显式文件,而不是难看的临时文件/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
Run Code Online (Sandbox Code Playgroud)

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

  • 比 -E 更优雅,因为我可以将 -save-temps 添加到 CFLAGS 而不改变构建脚本的整体行为。谢谢! (3认同)

小智 5

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

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

g++ -E .\Message.cpp > P1
Run Code Online (Sandbox Code Playgroud)

生成的 P1 文件已扩展宏,并且头文件内容和注释被删除。

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

g++ -S .\Message.cpp
Run Code Online (Sandbox Code Playgroud)

生成汇编程序 (ASM) (Message.s)。它有所有的汇编代码。

步骤 3:将汇编代码翻译为目标代码。注意:Message.s是在Step2中生成的。

g++ -c .\Message.s
Run Code Online (Sandbox Code Playgroud)

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

步骤 4:链接目标文件。这个任务是由链接器完成的

g++ .\Message.o -o MessageApp
Run Code Online (Sandbox Code Playgroud)

这里生成了一个exe文件MessageApp.exe。

#include <iostream>
using namespace std;

//This a sample program
int main()
{
  cout << "Hello" << endl;
  cout << PQR(P,K) ;
  getchar();
  return 0;
}
Run Code Online (Sandbox Code Playgroud)