Ответ 1
Да. Передайте gcc -E
. Это выведет предварительно обработанный исходный код.
Я использую библиотеку с открытым исходным кодом, которая, как представляется, имеет множество предпроцессорных директив для поддержки многих языков, отличных от C. Чтобы я мог изучить, что делает библиотека, мне бы хотелось увидеть код C, который я компиляция после предварительной обработки, больше похожа на то, что я бы написал.
Может ли gcc (или любой другой инструмент, обычно доступный в Linux) читать эту библиотеку, но выводить код C, который имеет предварительную обработку, преобразованную во что угодно и также читается человеком?
Да. Передайте gcc -E
. Это выведет предварительно обработанный исходный код.
cpp
является препроцессором.
Запустите cpp filename.c
, чтобы вывести предварительно обработанный код или, лучше, перенаправить его в файл с помощью
cpp filename.c > filename.preprocessed
.
Я использую GCC в качестве препроцессора (для HTML файлов.) Он делает то, что вы хотите. Он раскрывает директивы "# -", а затем выводит читаемый файл. (Ни один из других препроцессоров C/HTML, которые я пытался сделать, this- объединяет строки, задыхается от специальных символов и т.д.) Предполагается, что у вас установлен 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" сохраняет пробелы и табуляции.
Run:
gcc -E <file>.c
или
g++ -E <file>.cpp
-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
объекта -o
вместо текущего рабочего каталога, что позволяет избежать потенциальных конфликтов -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.
Предположим, у нас есть файл в виде 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
EXE файл MessageApp.exe создается здесь.
#include <iostream>
using namespace std;
//This a sample program
int main()
{
cout << "Hello" << endl;
cout << PQR(P,K) ;
getchar();
return 0;
}