[Linux] 리눅스에서의 C 프로그래밍

리눅스에서 C 프로그래밍 개발 환경 구축

GCC

  • GNU 프로젝트의 오픈 소스 컴파일러 집합
    • 1987, 리처드 스톨먼
    • GNU C Compiler의 약어로 시작
    • GNU Compiler Collection으로 변경: C(gcc), C++(g++), Objective-C(gobjc), D(gdc), Go(gccgo), Ada(gnat), Fortran(gfortran) 지원
  • 유닉스/리눅스 계열의 사실상 표준 컴파일러
    • Windows, BSDs 및 기타 OS에서도 사용 가능
    • 통합개발환경이라기보다는 명령행 모드에서 실행
    • vi로 작성 → gcc로 컴파일 → make로 빌드

 

개발환경 구축

1단계: 시스템 업데이트

  • 충돌 발생하지 않도록 모든 관련 패키지 업데이트
  • $ sudo apt update
    • sudo : 명령어 실행시 관리자 권한을 부여받기 위해
    • apt : 우분투(데비안 계열)의 SW 패키지 관리 프로그램 (advanced packaging tool)
    • update (apt 명령어의 옵션)

2단계: build essential 패키지 설치

  • GCC 패키지와 다른 응용 패키지로 구성
  • $ sudo apt install build-essential
    • install: apt 명령어의 옵션
    • build-essential : 설치할 패키지명

3단계: 설치 확인

  • 성공적인 설치를 위해 c 컴파일러 버전 확인
  • $gcc --version

 

하나의 소스파일로 구성된 C 프로그램의 작성

C 프로그램의 기본 작성

  1. vi 에디터로 소스 코드 작성
    • $ vi helloworld.c
  2. 컴파일하고 링크하기
    • $ gcc [-o <생성할 실행파일 명>] <소스파일명.c> : -o 옵션 생략시 a.out 이라는 이름으로 실행파일이 생성됨
    • $ gcc -o helloworld helloworld.c
  3. 실행하기
    • $ ./helloworld

 

다수의 소스 파일로 구성된 C 프로그램의 작성

컴파일/링크 과정

 

다수의 소스 파일로 구성된 예

 

인터페이스의 내용

  • Function prototype(함수 원형): 함수의 몸체({...}) 없이, 이름-입력값(매개변수)-출력값(반환형)만 선언한 것 (e. int add(int a, int b);)
  • Constant definition(상수 정의) (#define): 프로그램 전체에서 공통으로 사용할 변하지 않는 값 (e. #define MAX_BUFFER 1024)
  • Type definition(타입 정의) (typedef/struct) : 구조체 등을 사용하여 새로운 자료형을 만드는 것 (e. typedef struct { int x; int y;} Point; )
인터페이스(Interface) in C언어?
: .h(헤더 파일) 형태로 존재. 내가 짠 코드를 남이(또는 다른 파일이) 어떻게 써야 하는지 알려주는 공적인 약속

 

인터페이스 파일의 형식

: 하나의 인터페이스가 다양한 경로를 통해 여러 번 내포되더라도 컴파일러가 매번 다시 읽어들이지 않도록 하기 위해

#ifndef _headerFileName_h
#define _headerFileName_h

any required #include lines
interface entries

#endif
  • #ifndef _headerFileName_h : "If Not Defined"의 약자. 이 파일이 처음 로드되었는지 확인하는 관문. 만약 이미 한 번 로드되었다면(이미 정의되어 있다면), 바로 #endif로 점프해서 파일 내용을 무시한다.
  • #define _headerFileName_h : 지금부터 _headerFileName_h라는 이름표를 정의(Define)
  • any required #include lines : 이 인터페이스 파일이 제대로 작동하기 위해 필요한 다른 헤더 파일들을 가져온다.
  • interface entreis: 인터페이스의 3요소가 여기에 들어감. 실제 사용자에게 제공할 기능들을 나열하는 곳
  • #endif : #ifndef로 시작된 조건문(if)이 여기서 끝남

 

프로그램의 단계별 작성

: 한 프로그램이 여러 개의 소스 파일로 나뉘어 구성되어 있는 경우 좀 더 효율적으로 작성하기 위해

1. 컴파일하기 $ gcc -c <소스파일명.c> : 소스파일명.o의 이름으로 오브젝트 파일 생성

2. 링크하기 $ gcc [-o <실행파일명>] <오브젝트파일명.o> : -o 옵션 생략시 a.out 이라는 이름으로 실행파일이 생성 

 

단계별 작성

: 한 프로그램이 여러 개의 소스 파일로 나누어 구성되어 있는 경우

   - 특정 소스 코드가 수정된 경우 → 전체를 컴파일하지 않고서도 개발할 수 있어야 함

   - 각 소스파일이나 오브젝트 파일의 의존관계에 따라 필요한 파일만 재 컴파일하는 것이 필요

 

실습 예시

~$ mkdir multi
~$ cd multi
~/multi$ vi main.c
#include <stdio.h>
#include "simpio.h"

int main(void)
{
    int grade;
    
    printf("학년을 입력하시오: ");
    grade = GetInteger();
    
    printf("당신의 학년은 %d학년입니다.\n", grade);
    
    return 0;
}


:wq
~/multi$ vi simpio.h
#ifndef _SIMP_IO_H_
#define _SIMP_IO_H_

int GetInteger(void);

#endif
~/multi$ vi simpio.c
#include "simpio.h"
#include <stdio.h>

int GetInteger(void)
{
    int n;
    
    scanf("%d", &n);
    
    return n;
}


:wq
~/multi$ ls
main.c simpio.c simpio.h
~/multi$ gcc -o myprog main.c simpio.c
~/multi$ ls
main.c myprog simpio.c simpio.h
~/multi$ ./myprog
학년을 입력하시오: 3
당신의 학년은 3학년입니다.
~/multi$

 

자동 빌드 도구 make와 Makefile

make 유틸리티

: 프로그램 그룹을 유지하는데 필요한 유틸리티. 다수의 소스파일로 구성된 프로젝트에서 의존 관계에 따라 좀 더 효율적으로 개발하기 위해 사용

- build essential 패키지 내에 포함

- $ make [-f <메이크파일>]

 

Makefile

: make 명령 사용시 참조되는 파일

- 실행 파일을 만들기 위해 필요한 파일들 간의 상호 의존 관계생성 방법 등을 기술

- 어떤 이름도 가능하나 관례적으로 Makefile 혹은 makefile로 기술

 

Makefile의 구성 형식

target: dependencies commands

  • 목표(target) or 레이블(label)
    • 생성하고자 하는 목표(오브젝트 파일명이나 실행 파일명)
    • 명령이 수행되어 나온 결과 파일 (또는 동작에 대한 레이블)
  • 의존 관계 목록(dependencies) : 목표 생성시 필요한 파일명들
  • 명령 목록(commands)
    • 의존관계에 기술된 파일 변경시 목표 생성을 위한 명령어
    • 행의 시작이 탭 문자로 시작해야 함

 

Makefile의 작성 예

myprog: main.o simpio.o
        gcc -o myprog main.o simpio.o
        
main.o: simpio.h main.c
        gcc -c main.c
        
simpio.o: simpio.h simpio.c
        gcc -c simpio.c

- Makefile 이용 방법: $ make

 

Makefile 작성시 매크로 사용

: 특정한 표현을 간단하게 기술하기 위해 사용. 사용되기 전에 먼저 정의되어야 함!

OBJECTS = main.o simpio.o

myprog: $(OBJECTS)
        gcc -o myprog $(OBJECTS)
        
main.o: simpio.h main.c
        gcc -c main.c
        
simpio.o: simpio.h simpio.c
        gcc -c simpio.c

 

Makefile 작성시 레이블 사용

- 사용 방법: $ make clean

OBJECTS = main.o simpio.o

myprog: $(OBJECTS)
        gcc -o myprog $(OBJECTS)
        
main.o: simpio.h main.c
        gcc -c main.c
        
simpio.o: simpio.h simpio.c
        gcc -c simpio.c
        
clean:
        rm myprog $(OBJECTS)