gcc는 전처리 후 C 코드를 출력 할 수 있습니까?


104

C 이외의 많은 언어를 지원하기 위해 많은 사전 처리 지시문이있는 것처럼 보이는 오픈 소스 라이브러리를 사용하고 있습니다. 라이브러리가 무엇을하는지 연구 할 수 있도록 사전 처리 후 컴파일하는 C 코드를보고 싶습니다. , 내가 쓰는 것과 더 비슷합니다.

gcc (또는 Linux에서 일반적으로 사용할 수있는 다른 도구)가이 라이브러리를 읽을 수 있지만 전처리가 무엇이든 변환되어 사람이 읽을 수있는 C 코드를 출력 할 수 있습니까?


전처리 된 코드에는 더 이상 전 처리기 지시문이 없지만 전처리되기 전보다 훨씬 가독성이 떨어질 것이라고 확신합니다 ...
— Alex W

2
@AlexW-그것은 전적으로 코드를 작성하는 사람들이 전처리기를 얼마나 끔찍하게 남용했는지에 달려 있습니다 .
— 가짜 이름

1
여기에서 수락 된 답변을 변경해보십시오. gcc -E에서 작동하도록 줄을 다시 작성하는 것보다 더 유용합니다 cpp.
— Gray

답변:


193

예. gcc에 -E옵션을 전달하십시오. 이것은 전처리 된 소스 코드를 출력합니다.


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"는 공백과 탭을 유지합니다.


많은 감사합니다. 이것은 파이썬 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
빌드 스크립트의 전반적인 동작을 변경하지 않고 CFLAGS에 -save-temps를 추가 할 수 있기 때문에 -E보다 훨씬 더 우아합니다. 감사합니다!
— 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;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.