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.