Чи може вивести код Ccc після попередньої обробки?


104

Я використовую бібліотеку з відкритим кодом, яка, здається, має багато директив попередньої обробки для підтримки багатьох мов, крім C. Так що я можу вивчити, що робить бібліотека, я хотів би побачити код C, який я збираю після попередньої обробки , більше, як те, що я писав би.

Чи може gcc (або будь-який інший інструмент, широко доступний в Linux) читати цю бібліотеку, але виводить код C, який попередньо обробляв, перетворювався у будь-що, а також читається людиною?


У попередньо обробленому коді більше немає будь-яких директив препроцесора, але я впевнений, що він буде набагато менш читабельним, ніж перед попередньою обробкою ...
Alex W

2
@AlexW - Це повністю залежить від того, наскільки жахливо люди, які писали код, зловживали препроцесором.
Підроблене ім’я

1
Подумайте про зміну прийнятої відповіді тут. gcc -Eкорисніше, ніж переписувати рядок, щоб з ним працювати cpp.
Сірий

Відповіді:


193

Так. Передайте -Eопцію gcc . Це виведе попередньо оброблений вихідний код.


12
Якщо у ваших командах компілятора вже є такий параметр, який -o something.oви можете також змінити -o something.i. Інакше попередньо оброблений вихід буде у .oфайлі.
Tor Klingberg

@TorKlingberg Чи можу я зробити це для кількох файлів одночасно?
user2808264

@ user2808264gcc -E file1.c file2.c ...
Матьє

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

Це дійсно дуже корисно, і -E дуже зручно для одиночних файлів.
Субін Себастьян


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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.