build
1. 빌드와 실행
2. 간단한 gcc 명령어 살펴보기
1. 소스 코드
#include <stdio.h>
int main()
{
printf("Hello, World!\n");
return 0;
}
2. gcc 빌드 명령어
gcc test001.c // test.c → a.out 생성

- * 기호는 해당 파일이 "실행 가능한 파일(executable)"임을 나타내는 시각적 표시(리눅스 심볼)
- a.out의 .out 은 "기본 출력 실행 파일(auto output file)"을 의미, 확장자 .out이 아님
3. 빌드 과정과 gcc 컴파일 옵션
1. gcc 명령어 옵션별 역할과 생성된 파일 요약

옵션 | 설명 | 결과 | 생성되는 파일 예시 및 역할 |
-E | 전처리 과정까지만 수행 E = Expand (전처리 하여 코드 확장) |
test.i |
전처리된 소스 코드 출력 (.i 파일) |
-S | 어셈블리 코드까지 생성 S = Assembly (UNIX 전통) |
test.s | 어셈블리 코드 파일 생성 (.s 파일) |
-c | 목적 파일 생성 (컴파일+어셈블리) c = Compile only, no linking |
test.o | 목적 파일 생성 (.o 파일), 실행 파일은 생성하지 않음 |
-o <파일명> | 출력 파일명 지정 o = Output file name |
test.out | 컴파일 결과물(전처리, 어셈블리, 목적 파일, 실행 파일 등) |
2. -o 옵션 :
- Output file 출력 파일 이름 지정
- 기본적으로 gcc는 출력 파일을 a.out으로 생성
- -o 옵션을 사용하면 원하는 이름으로 실행파일명 설정 가능
- 링크 포함 실행파일 생성
4. 실습 요약
[실습1] 전처리된 소스파일 만들기

[실습2] 어셈블리 파일 만들기


[실습3] 목적 파일 만들기


[실습4] 실행 파일 만들기


5. 전처리된 소스파일 만들기 실습
1. 소스코드 파일을 전처리만 실행

gcc -E test.c -o test.i // test.c → test.i 생성
- test.i: 전처리된 텍스트 파일 (매크로 확장, 헤더 포함 완료)
2. 전처리된 소스 파일 확인하기

- 헤더 파일(예: <stdio.h>)에 정의된 수많은 선언과 매크로 정의가 모두 포함되어 있기 때문에 매우 방대합니다.
- test.i는 사람이 읽을 수 있는 순수 텍스트 파일로, 함수 선언, 구조체 정의, 매크로 확장 코드 등 헤더 전체 내용을 포함합니다
- 실제 실행에 필요한 최소한의 기계어 코드가 아니라, 소스코드 + 모든 포함 헤더 텍스트<stdio.h>를 전부 복사한 상태입니다. 따라서 크기가 더 크고, 컴파일 이후 생성된 바이너리(실행파일)보다 훨씬 용량이 큽니다.
3. printf() 함수의 선언부를 찾을 수 있습니다.

4. 전처리
- 컴파일 전 처리할 작업 수행
- #include "header.h"나 #include <stdio.h> 같은 헤더 파일 포함 지시문을 만나면,
해당 헤더 파일의 내용을 텍스트 수준에서 소스 코드에 복사 붙여넣기 합니다. - 프로그래밍의 편의를 위해 작성된 매크로 변환 (e.g. #define)
- 컴파일할 영역 명시 (e.g. #if, #ifdef, …)
- 전처리 지시자
지시자 | 사용 예 | 기능 |
#include | #include <stdio.h> | include 디렉터리에서 stdio.h를 찾아 그 내용 복사 |
#include "myhdr.h" | 소스 파일이 있는 디렉터리에서 myhdr.h를 찾아 그 내용 복사 |
|
#define | #define PI 3.14 | PI는 상수 3.14로 바뀜 |
#define SUM(x, y) ((x)+(y)) | SUM(10, 20)은 ((10)+(20))으로 바뀜 | |
#if ~ #endif | #if (VER >= 6) max = 1; #endif |
VER이 6 이상이면 max = 1; 컴파일 |
#ifdef ~ #endif | #ifdef DEBUG printf("%d", a); #endif |
DEBUG가 정의되어 있으면 printf 문장 컴파일 |
#ifndef ~ #endif |
#ifndef _POINT H_ #define _POINT_H_ (코드영역) #endif |
_POINT H_ 매크로명이 정의되어 있지 않으면 _POINT H_ 매크로명을 정의하고 (코드영역) ifndef 영역의 끝 표시 |
기타 | #else, #elif, #undef, #pragma, #error, #line 등 사용 가능 |
5. 실습
실제 소스코드를 작성하고,
#define 메크로 및 여러 파일로 분할된 소스코드를 전처리하여 어떻게 구성되는지 확인해보셔야 합니다.
6. 어셈블리 파일 만들기 실습
1. 소스코드 파일을 어셈블리 파일로 만들기 (전처리 + 컴파일)

gcc -S test.c -o test.s // test.c → test.s 생성
- test.s: 어셈블리어 코드 (사람이 읽을 수 있는 저수준 코드)
2. 전처리된 파일을 어셈블리 파일로 만들기

gcc -S test.i -o test.s // test.i → test.s 생성
- test.s: 어셈블리어 코드 (사람이 읽을 수 있는 저수준 코드)
3. 어셈블리 확인하기

- 링커를 수행하지 않고 중간 결과인 어셈블리어 코드를 생성합니다.
- test.s 파일에 사람이 읽을 수 있는 저수준 어셈블리 코드가 저장됩니다.
- 어셈블리 코드는 CPU 명령어와 레지스터, 메모리 주소 등을 표현한 코드입니다.
4. 어셈블리 예시

.file "test001.c" # 소스 파일 이름 표시 (디버깅 및 식별용)
.text # 실행 코드가 위치하는 섹션 시작
.section .rodata # 읽기 전용 데이터(Read-Only Data) 섹션 시작. 상수, 문자열 저장 공간
.LC0: # 라벨(Label). 상수 "Hello, World!" 문자열 위치 표시
.string "Hello, World!" # 문자열 상수를 저장
.text # 실행 코드 섹션 재시작
.globl main # main 함수를 전역 심볼로 선언 (링커가 참조 가능)
.type main, @function # main 심볼이 함수임을 표시
main:
.LFB0:
.cfi_startproc
- 어셈블리어는 기계어에 매우 가까운 저수준 언어로, 사람이 읽고 쓸 수 있는 형태
- 플랫폼(예: x86, ARM)마다 어셈블리 명령어와 문법이 다름
- 컴파일러가 고급언어를 어떻게 기계어 명령어로 변환하는지 감각 익히기
7. 목적 파일 만들기 실습
1. 목적 파일 만들기 (전처리 + 컴파일 + 어셈블링)

gcc -c test.c -o test.o // test.c → test.o 생성
- test.o: 목적 파일 (기계어, 바이너리, 이진수 코드가 담긴 중간 파일)
2. 어셈블리 파일을 목적(바이너리) 파일로 만들기

gcc -c test.s -o test.o // test.s → test.o 생성
- test.o: 목적 파일 (기계어, 바이너리, 이진수 코드가 담긴 중간 파일)
3. 바이너리 확인하기

VSCode에서 xxd처럼 파일의 이진(바이너리) 내용을 헥사 덤프(hexdump) 형태로 보려면
Hex Editor (by Microsoft) 확장 프로그램 설치
설치 후, 이진 파일을 우클릭 → Open With → Hex Editor 선택 가능

- -c는 링크 단계는 생략했기에, 최종 실행 파일을 만들지 않고, 중간 산출물인 목적 파일(object file, .o)을 생성
- .o 파일은 기계어(바이너리, 이진수) 코드가 담긴 목적 파일
- 플랫폼 의존적: 해당 CPU와 운영체제 아키텍처용 바이너리 코드 포함
- 대부분은 .s(텍스트 기반 어셈블리 코드) 크기가 훨씬 크고, .o(바이너리 목적 파일)는 용량이 작습니다.
- .o 파일은 단순 기계어 코드뿐 아니라 심볼 테이블, 디버깅 정보, 재배치 정보(relocation info), 섹션 헤더 등 여러 메타데이터를 포함하기 때문에 순수 명령어 텍스트인 .s보다 용량이 커질 수 있음
8. 실행 파일 만들기 실습과 링크
1 . 소스코드 파일을 실행 파일로 변환 (전처리 + 컴파일 + 어셈블링 + 링크)

gcc test.c -o test.out // test.c → test.out 생성
- test.out: 실행 가능한 바이너리 파일
2. 목적 파일을 실행 파일로 변환 실행

gcc test.o -o test.out // test.o → test.out 생성
- test.out: 실행 가능한 바이너리 파일
- * 기호는 해당 파일이 "실행 가능한 파일(executable)"임을 나타내는 시각적 표시
- a.out의 .out 은 "기본 출력 실행 파일(auto output file)"을 의미, 확장자 .out이 아님
3. 실행파일 확인하기

4. 링커의 역할
- 링커는 여러 목적 파일과 라이브러리(예: C 표준 라이브러리)를 결합하여 하나의 실행 파일을 만듦
- 링킹 과정에서 함수 참조를 해결하고, 필요한 라이브러리 코드도 포함시킴
- 라이브러리는 보통 목적 파일(Object file)들의 집합으로 구성됩니다.

5. mysql이나 stdio 라이브러리 연결 시
- 보통 libmysqlclient.a (정적) 혹은 libmysqlclient.so (동적) 형태로 제공됨
- stdio 같은 C 표준 라이브러리는 시스템에 따라 libc.a (정적), libc.so (동적) 형태로 있음
- 정적 라이브러리 .a는 목적 파일(.o) 묶음
- 정적 라이브러리면 링커가 .o 단위로 함수 구현 필요한 부분을 찾아서 실행 파일에 포함