내장형 하드웨어/C언어

컴파일 과정 수업 및 c언어 컴파일 에러 확인

동화다아아 2011. 3. 17. 13:50
 

컴파일 과정

소스( .c) → 전처리 (.i) → 컴파일(.s) → 어셈블러(.o or .obj) → 링크/링킹 → 실행파일 (.exe)

※ 밑줄 부분은 컴파일 과정에서 중간 파일이 생겼다가 지워진다.


중간 파일을 삭제하지 않고 보여주는 방법.

# gcc -v [--save-temps] -o test2 first.c


-v → 컴파일 과정을 화면에 출력한다.

--save-temps → 컴파일 과정에서 생성되는 중간 파일인 전처리 파일(*.i)과 어셈블리 파일(*.s)를 지우지 않고 현재 디렉토리에 저장한다. 컴파일 과정의 에러를 분석할 때 사용.

출력화면


 gcc -v [--save-temps] -o test2 first.c 명령으로 컴파일 한 후 출력해본 화면.


해당 디렉토리에 .i .s .o 의 파일과 실행파일이 생성되었다.


gcc 실행파일 생성 과정.

c 파일명을 abc.c  라고 가정하면 $gcc -o abc  abc.c 를 실행해서 abc  라는 실행 파일을 만드는 과정은 아래와 같다.

(cc1(컴파일러) 과 collect2(링커) 가 존재하는 위치는 gcc 버전마다 조금씩 다르다.)


1. 전처리  (abc.i  파일 생성)

 $cpp abc.c abc.i


2. 컴파일 (abc.s  어셈블러 파일 생성)

 $/usr/lib/gcc/i486-linux-gnu/4.0.2/cc1 abc.i


3. 목적코드 생성( abc.o 오브젝트 파일 생성)

 $as -V -Qy -o abc.o abc.s


4. 링킹 (ELF)

/usr/lib/gcc/i486-linux-gnu/4.0.2/collect2 --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o abc /usr/lib/gcc/i486-linux-gnu/4.0.2/../../../../lib/crt1.o /usr/lib/gcc/i486-linux-gnu/4.0.2/../../../../lib/crti.o /usr/lib/gcc/i486-linux-gnu/4.0.2/crtbegin.o -L/usr/lib/gcc/i486-linux-gnu/4.0.2 -L/usr/lib/gcc/i486-linux-gnu/4.0.2 -L/usr/lib/gcc/i486-linux-gnu/4.0.2/../../../../lib -L/usr/lib/gcc/i486-linux-gnu/4.0.2/../../.. -L/lib/../lib -L/usr/lib/../lib abc.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i486-linux-gnu/4.0.2/crtend.o /usr/lib/gcc/i486-linux-gnu/4.0.2/../../../../lib/crtn.o



링킹은 조금 복잡하다. 여기서 -dynamic-linker 는 동적 링킹으로 라이브러리를 로드한다는 의미이며 crt 라고 붙은 오브젝트 파일은 리눅스 시스템에서 파일을 실행할때 초기화와 종료시에 실행되는 것들이 들어 있다. -L 옵션은 그 뒤에 있는 경로를 라이브러리 경로로 사용하겠다는 의미 -lxx 옵션은 libxx.x 라는 라이브러리를 읽어들이겠다는 의미가 된다.



기본 옵션


gcc -W -Wall -O2 -o test test.c


-Wall → 모든 모호한 코딩에 대해서 경고를 보내는 옵션

-W → 합법적이지만 모호한 코딩에 대해서 경고를 보내는 옵션

-W -Wall → 아주 사소한 모호성에 대해서도 경고

-O2 → 최적화 레벨을 2로 설정 (거의 대부분의 최적화를 시도)

o test → 컴파일된 파일명을 test로 하라는 의미


gcc 옵션

gcc -E test.c


-E → 전처리 과정의 결과를 화면에 보이는 옵션. 전처리 과정 중에 발생한 오류를 검증할 때 사용하면 좋다.

※ 더 강력한 옵션: --save-temps → 생성되는 test.i 파일을 읽어보는 것이 더 좋은 방법.


gcc -S test.c

-S → cc1으로 전처리된 파일을 어셈블리 파일로 컴파일까지만 수행하고 멈춘다. test.s 파일이 만들어진다.

gcc -c test.c

-c → as에 의한 어셈블까지만 수행하고 링크는 하지 않음. test.o 까지만 만들어진다.

gcc -v test.c

-v → 컴파일 과정을 화면에 출력한다.

--save-temps → 컴파일 과정에서 생성되는 중간 파일인 전처리 파일(*.i)과 어셈블리 파일(*.s)를 지우지 않고 현재 디렉토리에 저장한다. 컴파일 과정의 에러를 분석할 때 사용.



c 수업 두 번째

#include <stdio.h>


int main()

{

        printf("1000\n");

        printf("%x\n",1000);

        printf("%o\n",1000);

        printf("%x\n",1000);


        return 0;

}


시그윈에서

gcc -o test1.exe main.c

./test1를 실행하면

 

숫자 1000을 입력하면 그대로 출력된다.

&d를 사용하면 10진수로 표시 - 1000

%o를 사용하면 8진수로 표시  - 1750으로 표시된다.

%x를 사용하면 16진수로 표시 - 3e8로 표시된다.



컴파일 과정 확인

소스(□.c) → 전처리(□.i) → 컴파일(□.s) → 어셈블리(□.o or .obj) → 실행파일(□.exe)


예제


첫 번째 빨간 사각형 안은 전처리 과정 중 에러가 발생한 것이다.

main.c:1:2 에서 1:2는 첫째줄과 둘째줄에서 에러가 발생했다는 뜻이고

invalid preprocessing directive #nclude 는 지시어가 명령한 #nclude가 전처리 과정중에 잘못되었다는 뜻이다.

directive는 컴퓨터 용어로 지시어(지시자)라는 뜻이 있다. 즉, 전처리기에 명령을 내린다.


두 번째 빨간 사각형 안은 컴파일 단계에서 에러가 발생한 것이다.

main.c:3: error: parse error before "main" 이라는 것은 main함수 앞에서 에러구문이 발생했다는 뜻.


세 번째 빨간 사각형 안 역시 컴파일 단계에서 에러가 발생했다.

main.c:3: error: parse erroe before ')' token 은 역시 main()에서 (이 빠져서 나온 에러가 표시된 것으로 token이란 기호에 의미가 부여되니 것들을 말한다 할 수 있다. 예를 들면 ;,(,{, 철수가, 집에, 등등 기호에 의미가 부여되어 있을 때 이것을 토큰이라 할 수 있다.)


※ 항상 에러의 해결은 에러 발생의 첫줄부터 시작한다. 첫 번째 에러로 인해 나머지 에러들이 발생한 것일 수가 있기 때문이다. 세 번째 빨간 사각형의 경우에서도 ‘(’를 빼먹었을 뿐이지만 뒤에 있는 모든 C 구문이 에러가 났다.


- 컴파일러 단계(Parser)에서 에러의 85% 이상이 발생한다.

- 나머지는 전처리 단계에서 10% 정도 링크/링킹 단계에서 5%정도의 에러가 발생.


참고 -토큰 (token)-


어휘(Token)

        프로그램을 구성하고 있는 문법적으로 의미 있는 최소 단위

        문장 “if (i<100) sum+=i;” 은 10개의 토큰으로 이루어짐 
         -> if, (, i, <, 100, ), sum, +=, i, ;

      Mobile C 언어의 토큰

 

[참고]

gcc 컴파일 옵션(http://ssulsamo.egloos.com/5247105)

리눅스 gcc 실행파일 만들기 과정

(http://blog.naver.com/ohpowel?Redirect=Log&logNo=80024570104)