gcc สามารถส่งออกรหัส C หลังจากประมวลผลล่วงหน้าได้หรือไม่?


106

ฉันใช้ไลบรารีโอเพ่นซอร์สซึ่งดูเหมือนว่าจะมีคำสั่งก่อนการประมวลผลจำนวนมากเพื่อรองรับหลายภาษานอกเหนือจากภาษา C เพื่อที่ฉันจะได้ศึกษาว่าห้องสมุดกำลังทำอะไรอยู่ฉันต้องการดูรหัส C ที่ฉันรวบรวมหลังจากการประมวลผลล่วงหน้า เหมือนสิ่งที่ฉันเขียน

gcc (หรือเครื่องมืออื่น ๆ ที่มีอยู่ทั่วไปใน Linux) สามารถอ่านไลบรารีนี้ได้ แต่เอาท์พุทโค้ด C ที่มีการประมวลผลล่วงหน้าแปลงเป็นอะไรก็ได้และมนุษย์ยังอ่านได้ด้วย?


รหัสก่อนประมวลผลจะไม่มีคำสั่งก่อนตัวประมวลผลอีกต่อไป แต่ฉันค่อนข้างแน่ใจว่ามันจะอ่านได้น้อยกว่าก่อนที่จะประมวลผลล่วงหน้าอย่างมาก ...
Alex W

2
@AlexW - ที่ขึ้นอยู่ทั้งหมดเกี่ยวกับวิธีที่น่ากลัวคนเขียนโค้ดทำร้ายพรีโพรเซสเซอร์
ชื่อปลอม

1
โปรดพิจารณาเปลี่ยนคำตอบที่คุณยอมรับที่นี่ gcc -Eมีประโยชน์มากกว่าการเขียนบรรทัดใหม่เพื่อให้ใช้งานcppได้
สีเทา

คำตอบ:


197

ใช่. ผ่าน-Eตัวเลือกgcc สิ่งนี้จะส่งออกซอร์สโค้ดที่ประมวลผลล่วงหน้า


14
หากคำสั่งคอมไพเลอร์ของคุณมีพารามิเตอร์อยู่แล้วเช่น-o something.oคุณอาจต้องการเปลี่ยนเป็น-o something.i. มิฉะนั้นเอาต์พุตที่ประมวลผลล่วงหน้าจะอยู่ใน.oไฟล์
Tor Klingberg

@TorKlingberg ฉันสามารถทำได้ครั้งละหลายไฟล์หรือไม่
user2808264

@ user2808264gcc -E file1.c file2.c ...
Matthieu

69

cpp เป็นตัวประมวลผลล่วงหน้า

เรียกใช้cpp filename.cเพื่อส่งออกโค้ดที่ประมวลผลล่วงหน้าหรือดีกว่าเปลี่ยนเส้นทางไปยังไฟล์ที่มี cpp filename.c > filename.preprocessed.


3
ฉันคิดว่านี่เป็นคำตอบที่ดีที่สุดเพราะมันแสดงให้เห็นถึง 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

เป้าหมายที่กำหนดไว้ล่วงหน้าของ 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


1
สวยกว่า -E มากเพราะฉันสามารถเพิ่ม -save-temps ให้กับ CFLAGS ได้โดยไม่ต้องเปลี่ยนพฤติกรรมโดยรวมของบิลด์สคริปต์ ขอบคุณ!
EvertW

สิ่งนี้มีประโยชน์มากและ -E สะดวกมากสำหรับไฟล์เดียว
Subin Sebastian


1

สมมติว่าเรามีไฟล์เป็น Message.cpp หรือไฟล์. c

ขั้นตอนที่ 1: การประมวลผลล่วงหน้า (อาร์กิวเมนต์ -E)

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

ไฟล์ P1 ที่สร้างขึ้นมีมาโครขยายและเนื้อหาของไฟล์ส่วนหัวและความคิดเห็นถูกตัดออก

ขั้นตอนที่ 2:แปลไฟล์ที่ประมวลผลล่วงหน้าเป็นแอสเซมบลี (Argument -S) งานนี้ทำโดยคอมไพเลอร์

g ++ -S. \ Message.cpp

แอสเซมเบลอร์ (ASM) ถูกสร้างขึ้น (Message.s) มันมีรหัสการประกอบทั้งหมด

ขั้นตอนที่ 3:แปลรหัสประกอบเป็นรหัสวัตถุ หมายเหตุ: Message.s ถูกสร้างขึ้นในขั้นตอนที่ 2 g ++ -c. \ Message.s

ไฟล์ออบเจ็กต์ที่มีชื่อ Message.o ถูกสร้างขึ้น มันคือรูปแบบไบนารี

ขั้นตอนที่ 4: การเชื่อมโยงไฟล์ออบเจ็กต์ งานนี้ทำโดย linker

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;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.