battle_c
Jangwon Lee - Team 3
실전코딩2
printf
int printf(const char *format, ...)
printf 함수는 매개변수를 format에 따라서 출력해주는 함수다.
int fprintf(FILE *stream, const char *format, ...)
printf 함수는 실행될 때 내부에서 fprintf 함수로 바뀌어서 실행된다.
printf("Hello World");
fprintf(stdout, "Hello World");
printf 함수가 fprintf 함수로 바뀔 때 stream에 stdout이 들어가게 되고 두 함수는 완전히 같은 역할을 한다.
stdio.h
standard input output library의 줄임말로 표준 입출력과 관련된 함수, 매크로 등이 포함된 헤더 파일이다.
stream
-
stdin
표준 입력 스트림(키보드)를 참조하는 FILE에 대한 포인터 -
stdout
표준 출력 스트림(스크린)를 참조하는 FILE에 대한 포인터 -
stderr
표준 오류 스트림(스크린)를 참조하는 FILE에 대한 포인터
man
man <command | function | header file | ...>
manual의 줄임말로 명령어나 함수, 헤더 파일 등에 대한 사용법을 알려주는 명령어다.
redirection
redirection이란 스트림의 흐름을 바꿔주는 것이다. redirection을 이용해 프로세스의 스트림을 콘솔이 아닌 파일을 사용할 수 있다.
- >
file > output
표준 출력을 파일로 redirection한다. 파일이 없으면 새로 만들고, 파일이 있으면 덮어쓴다.
$ ./test > output_data
- >>
file >> output
표준 출력을 파일로 redirection한다. 파일이 없으면 새로 만들고, 파일이 있으면 파일의 끝에 덧붙인다.
$ ./test >> output_data
- <
file < input
파일로부터 표준 입력을 받도록 redirection한다.
$ ./test < intput_data
C Preprocessor
전처리기(preprocessor)는 전처리(.c -> .i)를 해주는 도구이다. 전처리는 .h에 있는 텍스트들을 .c에 치환(붙여넣기)해주는 과정이다. C Preprocessor는 CPP로 줄여쓰기도 한다.
Including files
-
#include <filename>
표준 헤더 파일을 include하는 방식으로 표준 라이브러리들이 모여있는 폴더에서 헤더 파일을 검색해서 include한다. -
#include "filename"
사용자 헤더 파일을 include하는 방식으로 현재 소스 파일이 위치한 폴더에서 헤더 파일을 검색해서 include한다.
Conditional compilation
#if, #ifdef, #ifndef, #else, #elif, #endif는 조건부 컴파일을 할 수 있게 한다. 조건이 맞지 않으면 그 부분이 컴파일에서 제외된다. 즉, 소스 자체가 없는 효과가 있다. #error을 사용하여 컴파일을 실패하게 할 수도 있다.
Macro definition
특정 숫자, 함수, 프로그램 블록을 다른 형태로 변환 지정한다. 변환은 원래 한 줄만 가능하지만 \를 사용하여 여러 줄을 연결할 수 있다.
-
#define <identifier> <replacement token list>
대상변환형(Object-like macros)이라고 하며 identifier를 replacement token list로 변환한다. -
#define <identifier>(<parameter list>) <replacement token list>
유사함수변환형(Function-like macros)이라고 하며 identifier와 parameter list를 replacement token list로 변환한다. -
#undef <identifier>
#undef를 사용해 정의된 매크로를 무효화할 수도 있다.
#define f(a) a*a
b = f(20+13) // b = 293
전처리는 단순히 텍스트를 치환하는 것이기 때문에 위의 코드를 실행할 시
b = 20 + 13 * 20 + 13
이렇게 치환되므로 괄호를 최대한 많이 써주는 것이 좋다.
#define f(a) ((a)*(a))
b = f(20+13) // b = 1089
etc.
-
#pragma once
#pragma once
를 사용하여 여러번 include하는 것을 방지할 수 있다. -
Token stringification
#define <identifier>(<parameter>) #parameter
#연산자는 token을 문자열 상수로 변환한다. -
Token concatenation
#define <identifier>(<parameter>) parameter##string
##연산자는 두 token을 하나로 연결하여 변환한다. -
Debuging macros
디버깅을 하면서 어느 부분에서 에러가 났는 지 알려준다.- __FILE__
에러가 발생한 파일 경로 - __LINE__
에러가 발생한 라인 - __FUNCTION__
에러가 발생한 함수
- __FILE__
Multiple file compile
- func.h
#define SQAURE(a) ((a)*(a))
extern int func(int a);
- func.c
#include "func.h"
int func(int a)
{
return(a * 10);
}
- main.c
#include <stdio.h>
#include "func.h"
int main()
{
printf("func(100): %d SQUARE(10): %d\n", func(100), SQUARE(10));
return 0;
}
보통 이런 식으로 코드를 작성하고
$ gcc main.c func.c
이렇게 컴파일, 링크하여 실행 파일을 실행한다.
컴파일러 vs 인터프리터
컴파일러와 인터프리터는 고급언어로 작성된 원시 프로그램(Source Program)을 목적 프로그램(Object Program)으로 번역하는 번역 프로그램이며, 프로그램 번역 방식에 따라 구분된다.
컴파일러
- 컴파일러는 고급 언어로 작성된 프로그램 전체를 목적 프로그램으로 번역한 후, 링킹 작업을 통해 컴퓨터에서 실행 가능한 실행 프로그램을 생성한다.
- 번역 실행 과정을 거쳐야 하기 때문에 번역 과정이 번거롭고 번역 시간이 오래 걸리지만, 한번 번역한 후에는 다시 번역하지 않으므로 실행 속도가 빠르다.
- 컴파일러를 사용하는 언어에는 C언어 Java 등이 있다.
인터프리터
- 인터프리터는 고급 언어로 작성된 프로그램을 한 줄 단위로 받아들여 번역하고, 번역과 동시에 프로그램을 한 줄 단위로 즉시 실행시키는 프로그램이다.
- 프로그램이 직접 실행되므로 목적 프로그램은 생성되지 않는다.
- 줄 단위로 번역, 실행되기 떄문에 시분할 시스템에 유용하며 원시 프로그램의 변화에 대한 반응이 빠르다.
- 번역 속도는 빠르지만 프로그램 실행 시 매번 번역해야 하므로 실행 속도는 느리다.
- CPU의 사용시간의 낭비가 크다.
- 인터프리터를 사용하는 언어에는 Python, BASIC, SNOBOL, LISP, APL등이 있다.
차이점
컴파일러 | 인터프리터 | |
---|---|---|
번역단위 | 전체 | 행(줄) |
목적 프로그램 | 생성함 | 생성하지 않음 |
실행 속도 | 빠름 | 느림 |
번역 속도 | 느림 | 빠름 |
관련 언어 | C, Java | Python, BASIC, LISP, APL, SNOBOL |
GCC 명령어 옵션
-
-o
지정한 파일명에 출력한다$ gcc -o 00.option-o 00.option-o.c
-
-E
전처리하여 전처리된 소스 파일(.i)을 생성한다$ gcc -E 01.option-E.c
-E 옵션만 사용하면 전처리된 결과를 stdout에 보여주기만 한다.
$ gcc -E 01.option-E.c > 01.option-E.i
-
-S
컴파일하여 어셈블리 파일(.s)을 생성한다$ gcc -S 02.option-S.i
-
-c
어셈블하여 목적 파일(.o)을 생성한다$ gcc -c 03.option-c.s
-
-D
외부에서 매크로를 define한다$ gcc -DNO 05.option-D.c
-
-g
운영체제 고유의 형식으로 디버깅 정보를 만든다$ gcc -g 06.option-g.c
-
-Wall
GCC가 제공할 수 있고, 일반적으로 유용한 모든 경고 메시지 출력한다$ gcc -Wall 07.option-Wall.c
-
-I(upper case of i)
헤더 파일을 검색할 디렉터리를 추가한다$ gcc -ImyInclude 09.option-I.c
Make
make란?
- 프로그램 그룹 중에서 어느 부분이 새롭게 컴파일 되어야 하는지를 자동적으로 판단해서 필 요한 커맨드를 사용해서 그들을 재 컴파일 시킴
- 많은 프로그램 모듈들로 구성된 대규모 프로그램을 효율적으로 유지하고, 일관성 있게 관리 하도록 도와주는 도구
- 소스 수정 시 유관 파일들을 재컴파일 & 링크하는 반복적인 작업을 간단하게 처리함
- 선결조건(prerequisites)으로부터 대상(target)을 만들어 내는 다목적 프로그램
make의 동작
- make는 여러 파일들 간의 의존성을 저장하고 수정된 파일에 연관된 소스 파일들만을 재 컴파일 하도록 해줌
- 수정한 소스 파일들만 자동적으로 재 컴파일하고 링크하도록 함
- 소스 수정 시 유관 파일들을 재컴파일 & 링크하는 반복적인 작업을 간단하게 처리함
- make 유틸리티는 이전에 make 명령을 실행했던 시점 이후에 이뤄진 프로젝트 작업들에 대해서만 갱신 작업을 수행함
make의 필요성
- 프로그램 개발 및 유지보수의 편리성을 지원
- 명령어의 배치 처리 가능, 자주 쓰는 명령어를 자동화할 수 있음
- 입력파일 변경 시 자동적으로 결과 파일이 바뀌기를 원할 때
Makefile
대상(target) : 의존하는 파일들(prerequisites)
<tab> 명령어(command)
<tab> 명령어(command)
-
clean 주로 make하는 과정에서 생긴 .o 파일이나 실행 파일을 삭제하는 역할
-
dep gccmakedep 명령어를 통해 의존 관계를 자동으로 생성한다.
<identifier> = <files>
identifier를 통해 여러 개의 파일들을 간단하게 부를 수 있는 매크로
코드 상에서 쓸 때는 $(<identifier>)
로 써야 한다.
- 내장매크로(Internal macro)
매크로 | 의미 |
---|---|
$@ | 현재의 목표 (Target) 파일명 |
$? | 현재의 목표파일(Target)보다 더 최근에 갱신된 의존 파일 명단 |
$* | 현재의 목표파일(Target)보다 더 최근에 갱신된 확장자를 제외한 의존 파일 명단 |
$< | 의존 파일(전제 조건) 중 첫번째 파일명 |
$^ | 현재 모든 의존 파일들의 명단 |
$+ | '$^'과 같지만, 두 번 이상 나열된 전제 조건은 makefile에 나열된 순서대로 복제됨 |
$% | 타깃이 라이브러리 모듈일 때 멤버에 대응되는 파일명 |
- 내장매크로(Pre-defined macro)
매크로 | 의미 |
---|---|
AR | Archive-maintaining program; default ‘ar’. |
ARFLAGS | ar 명령어의 옵션 설정 |
AS | Program for compiling assembly files; default ‘as’. |
ASFLAGS | as 명령어의 옵션 설정 |
CC | Program for compiling C programs; default ‘cc’. |
CFLAGS | cc 명령어의 옵션 설정 |
CXX | Program for compiling C++ programs; default ‘g++’. |
CXXFLAGS | g++ 명령어의 옵션 설정 |
LDFLAGS | ld 명령어의 옵션 설정 |
- 확장자 규칙 (Suffix Rules) 확장자 규칙은 미리 정의해 놓은 일반화한 기술 파일 항목을 가리킴
.SUFFIXES : .o .c .s
.c.o :
$(CC) $(CFLAGS) -c $<
.s.o :
$(AS) $(ASFLAGS) -o $@ $<
ledTest
led thread
led_main
./led_main
led main task start
red ON
red OFF
red ON
red OFF
red ON
red OFF
red ON
red OFF
red ON
red OFF
red ON
red OFF
red ON
red OFF
red ON
red OFF
red ON
red OFF
red ON
red OFF
led main task end
led red blinked 10 times
led_main 1 5
./led_main 1 5
led main task start
red ON
led blue task start
blue ON
red OFF
blue OFF
red ON
red OFF
blue ON
red ON
red OFF
blue OFF
red ON
red OFF
blue ON
red ON
red OFF
blue OFF
red ON
red OFF
blue ON
red ON
red OFF
blue OFF
red ON
red OFF
blue ON
red ON
red OFF
blue OFF
red ON
red OFF
led blue task end
led main task end
led red blinked 10 times
led blue blinked 5 times
led_main_2_3
./led_main 2 3
led main task start
red ON
led orange task start
orange ON
red OFF
red ON
orange OFF
red OFF
red ON
red OFF
orange ON
red ON
red OFF
red ON
orange OFF
red OFF
red ON
red OFF
orange ON
red ON
red OFF
red ON
orange OFF
red OFF
red ON
red OFF
led orange task end
red ON
red OFF
led main task end
led red blinked 10 times
led orange blinked 3 times
led_main_3_3
./led_main 3 3
led main task start
red ON
led orange task start
orange ON
led blue task start
blue ON
red OFF
red ON
blue OFF
orange OFF
red OFF
blue ON
red ON
red OFF
orange ON
blue OFF
red ON
red OFF
blue ON
red ON
orange OFF
red OFF
blue OFF
red ON
red OFF
orange ON
led blue task end
red ON
red OFF
red ON
orange OFF
red OFF
red ON
red OFF
led orange task end
red ON
red OFF
led main task end
led red blinked 10 times
led blue blinked 3 times
led orange blinked 3 times
Static test
before modify
after modify
Dynamic test
coverage
ArrayTest, inputVarTest, staticVarTest의 coverage를 100%까지 향상시켰다.
MC/DC
ArrayTest, inputVarTest의 MC/DC를 100%까지 향상시켰다.