126

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

gcc(或 Linux 中常用的任何其他工具)能否读取该库但输出的 C 代码已将预处理转换为任何内容并且也可供人类阅读?

4

6 回答 6

220

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

于 2011-02-04T17:19:56.797 回答
76

cpp是预处理器。

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

于 2011-02-04T17:19:51.293 回答
21

我使用 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”保留空格和制表符。

于 2017-02-19T17:29:12.957 回答
19

-save-temps

这是另一个很好的选择:

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

主程序

#define INC 1

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

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

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

    # 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 中测试。

CMake 预定义目标

CMake 自动为预处理文件提供一个目标:

make help

向我们展示了我们可以做到:

make main.i

并且该目标运行:

Preprocessing C source to CMakeFiles/main.dir/main.c.i
/usr/bin/cc    -E /home/ciro/bak/hello/main.c > CMakeFiles/main.dir/main.c.i

所以文件可以在CMakeFiles/main.dir/main.c.i

在 cmake 3.16.1 上测试。

于 2019-04-02T14:34:38.897 回答
12

跑:

gcc -E <file>.c

或者

g++ -E <file>.cpp
于 2017-07-07T18:50:01.573 回答
3

假设我们有一个 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;
}
于 2019-06-13T13:09:59.217 回答