Может ли gcc вывести код C после предварительной обработки? - PullRequest
84 голосов
/ 04 февраля 2011

Я использую библиотеку с открытым исходным кодом, которая, кажется, имеет много директив предварительной обработки для поддержки многих языков, кроме C. Чтобы я мог изучить, что делает библиотека, я хотел бы увидеть код на C, компиляция после предварительной обработки, больше похоже на то, что я напишу.

Может ли gcc (или любой другой инструмент, обычно доступный в Linux) читать эту библиотеку, но выводить код C, в котором предварительная обработка преобразуется во что угодно и также читаема человеком?

Ответы [ 6 ]

177 голосов
/ 04 февраля 2011

Да. Передайте gcc опцию -E. Это выведет предварительно обработанный исходный код.

62 голосов
/ 04 февраля 2011

cpp - препроцессор.

Запустите cpp filename.c для вывода предварительно обработанного кода или, лучше, перенаправьте его в файл с помощью cpp filename.c > filename.preprocessed.

13 голосов
/ 19 февраля 2017

Я использую gcc в качестве препроцессора (для html-файлов). Он делает то, что вы хотите. Он раскрывает директивы "# -", а затем выводит читаемый файл. (Ни один из других препроцессоров C / HTML, которые я пытался сделать, делает это - они объединяют строки, задыхаются от специальных символов и т. Д.) Если вы установили gcc, командная строка:

gcc -E -x c -P -C -traditional-cpp code_before.cpp> code_after.cpp

(не обязательно должен быть 'cpp'.) Отличное описание этого использования: http://www.cs.tut.fi/~jkorpela/html/cpre.html.

"-traditional-cpp" сохраняет пробелы и символы табуляции.

8 голосов
/ 07 июля 2017

Прогон:

gcc -E <file>.c

или

g++ -E <file>.cpp
5 голосов

-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 голос
/ 13 июня 2019

Предположим, у нас есть файл в виде Message.cpp или .c файл

Шаги 1: Предварительная обработка (аргумент -E)

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

Сгенерированный файл P1 содержит расширенные макросы, содержимое заголовочного файла и комментарии удалены.

Шаг 2: Перевести предварительно обработанный файлна сборку (Аргумент -S).Эта задача выполняется компилятором

g ++ -S. \ Message.cpp

Генерируется ассемблер (ASM) (Message.s).Он содержит весь код сборки.

Шаг 3: Переведите код сборки в объектный код.Примечание. Message.s был сгенерирован на шаге 2. g ++ -c. \ Message.s

Создается объектный файл с именем Message.o.Это двоичная форма.

Шаг 4: Связывание объектного файла.Эта задача выполняется компоновщиком

g ++. \ Message.o -o MessageApp

Здесь создается исполняемый файл MessageApp.exe.

#include <iostream>
using namespace std;

 //This a sample program
  int main()
{
cout << "Hello" << endl;
 cout << PQR(P,K) ;
getchar();
return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...