텍스트로 작성한 프로그램을 시스템이 이해할 수 있는 기계어로 변환하는 과정
gcc main.o foo.o bar.o -o a.out
기능 = C 프로그램을 컴파일해 실행 파일을 생성
형식 = gcc [옵션][파일명]
옵션
-c
: 오브젝트 파일(.o)만 생성
-o
실행 파일명 : 지정한 이름으로 실행 파일을 생성, 기본 실행 파일명은 a.out
사용 예:
$ gcc test.c
$ gcc -c test.c
$ gcc -o test test.c
[예제]
$ gcc ch1_2.c
$ ls
a.out ch1_2.c
$ gcc –o ch1_2.out ch1_2.c
$ ls
a.out ch1_2.out ch1_2.c
실행 파일명을 ch1_2.out이라 하려면 -o
옵션을 사용
실행 파일명을 입력하면 프로그램이 실행
현재 디렉터리(.)가 경로에 설정되어 있지 않다면 현재 디렉터리를 지정해 실행
이후에는 현재 디렉터리가 경로에 있다고 가정하여 ./
를 표시하지 않음.
$ ch1_2.out (현재 디렉터리가 경로에 있을 경우)
(또는)
$ ./ch1_2.out (현재 디렉터리가 경로에 없을 경우
Makefile
: 컴파일 명령, 소스 파일을 컴파일하는 방법, 링크할 파일, 실행 파일명 등을 설정 하는 파일make
명령 : Makefile을 읽고 이 파일에서 지정한대로 컴파일을 실행해 실행 파일을 생성$ sudo apt install make
Makefile은 대상(Target), 의존 관계(Dependency), 명령(Recipe)의 세 가지로 이뤄진다.
<Target> : <Dependency>
(tab)<Recipe>
빌드 대상 이름. 명령에 의해 생성되는 결과 파일, 오브젝트 파일이나 실행 파일
대상을 만들 때 의존되는 파일들. 여기에 나열된 대상들을 먼저 만들고 빌드 대상을 생성한다.
주어진 타겟을 make 할 때 실행할 명령어들의 나열
CC = <컴파일러>
CFLAGS = <컴파일 옵션>
LDFLAGS = <링크 옵션>
LDLIBS = <링크 라이브러리 목록>
OBJS = <Object 파일 목록>
TARGET = <빌드 대상 이름>
all : $(Target)
clean :
rm -f *.o
rm -f $(TARGET)
$(TARGET) : $(OBJS)
$(CC) -o $@ $(OBJS)
[예시]
# Makefile
CC=gcc
CFLAGS=
OBJS=ch1_3_main.o ch1_3_addnum.o
LIBS=
all : add.out
add.out : $(OBJS)
$(CC) $(CFLAGS) -o add.out $(OBJS) $(LIBS)
ch1_3_main.o : ch1_3_main.c
$(CC) $(CFLAGS) -c ch1_3_main.c
ch1_3_addnum.o : ch1_3_addnum.c
$(CC) $(CFLAGS) -c ch1_3_addnum.c
clean:
rm -f $(OBJS) add.out *.o core
클린(Clean) 매크로
rm -f
빌드 결과물(ex. a.out)과 중간 부산물들(*.o)을 모두 삭제하여 깨끗한 상태에서 다시 빌드할 수 있는 환경을 만들어준다.
rm - rf
recursive로 모든 파일 삭제.
#include <stdio.h>
void perror(const char *s)
s
: 출력할 문자열
perror() 함수의 특징
[예시]
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
int main() {
if(access("test.txt", R_OK) == -1) {
perror("test.txt");
exit(1);
}
}
[결과]
$ ch1_4.out
test.txt: No such file or directory
#include <string.h>
char *strerror(int errnum);
errnum
: errno 에 저장된 값[예시]
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
extern int errno;
int main() {
char *err;
if(access("test.txt", R_OK) == -1) {
err = strerror(errno);
printf("오류: %s(test.txt)\n", err);
exit(1);
}
}
[결과]
$ ch1_5.out
오류: No such file or directory(test.txt)
#include <stdlib.h>
void *malloc(size_t size);
size
: 할당받을 메모리 크기
인자로 지정한 크기의 메모리를 할당하는 데 성공하면 메모리의 시작 주소를 리턴
만약 메모리 할당에 실패하면 NULL 포인터를 리턴
인자로 지정하는 메모리 크기는 바이트 단위
할당된 메모리에는 어떤 형태의 데이터도 저장할 수 잇음
malloc() 함수는 할당된 메모리를 초기화하지 않는다
char *ptr;
ptr = malloc(sizeof(char) * 100);
#include <stdlib.h>
void *calloc(size_t nmemb, size_t size);
nmemb
: 배열 요소의 개수
size
: 할당받을 메모리 크기
calloc() 함수는 nmemb * sizze 바이트 크기의 배열을 저장할 메모리를 할당
calloc() 함수는 할당된 메모리를 0으로 초기화
ex) 요소가 10개이고 각 요소의 크기가 20바이트인 배열을 저장할 수 있는 메모리를 할당
char *ptr
ptr = calloc(10, 20);
#include <stdlib.h>
void *realloc(void *ptr, size_t size);
ptr
: 할당받은 메모리를 가리키는 포인터
size
: 할당받은 메모리 크기
realloc() 함수는 이미 할당받은 메모리에 추가로 메모리를 할당할 떄 사용
이전에 할당받은 메모리와 추가할 메모리를 합한 크기의 메모리를 새롭게 할당하고 주소를 리턴
이때 이전 메모리의 내용을 새로 할당된 메모리로 복사
ex) malloc() 함수로 할당받은 메모리에 추가로 100바이트를 할당하는 예
char *ptr, *new;
ptr = malloc(sizeof(char) * 100);
new = realloc(ptr, 100);
#include <stdlib.h>
void free(void *ptr);
ptr
: 해제할 메모리 주소main() 함수에서 명령행 인자를 전달받으려면 다음과 같이 정의
int main(int argc, char *argv[]){ ... }
[예시]
#include <stdio.h>
int main(int argc, char *argv[]){
int n;
printf("argc = "%d\n", argc);
for(n = 0; n < argc; n++)
printf("argv[%d] = %s\n", n, argv[n]);
}
[결과]
$ ch1_6.out -h 2000
argc = 3
argv[0] = ch1_6.out
argv[1] = -h
argv[2] = 2000