실전코딩 2 실습
sshid : pcc004
name : 김나영
id : 202126850
Lecture 01 [2022.01.04]
Linux command
- ls (ls -l, ls -al 등의 형태)
- 현재 directory에 있는 파일 리스트 확인 가능
- ls -l : ls 명령어보다 상세한 파일 정보를 제공
- ls -al (ls -la) : directory에 있는 모든 파일 정보를 보여줌
- .으로 시작하는 hidden file(숨겨진 파일)까지 확인할 수 있음
- date
- 현재 시간(시, 분, 초)와 날짜 및 요일에 대한 정보를 제공
- who
- 현재 컴퓨터에 접속 중인 id 목록을 보여줌
- ~~ | sort
- ~~ 내용을 정렬된 상태로 보여줌
- ~~ | wc
- word count
- line수 단어수 글자수(공백과 줄바꿈 포함) 정보 제공
- pwd
- 현재 작업 중인 directory의 절대 경로를 제공
- cd
- change directory
- directory의 위치를 변경
- mkdir
- 새로운 directory 생성
- vi ~~
- 기존에 ~~ 파일이 없는 경우 파일을 생성하고 vi editor 모드로 변환됨
- 기존에 ~~ 파일이 있는 경우 ~~ 파일을 vi editor 모드로 보여줌
- cc ~~
- ~~ 파일을 컴파일
- passwd
- 비밀번호 변경 명령어
- rm ~~
- ~~ 파일을 제거
- rmdir ~~
- ~~ directory를 제거
- cat
- 파일 내용을 출력
- 파일이 존재하지 않는 경우
- standard input을 받은 후 standard output으로 내보냄
- 파일이 존재하는 경우
- 파일을 합침
-
cat data.txt hello.c output.txt > total.txt
- data.txt, hello.c, output.txt 파일의 내용을 total.txt 파일에 저장.
- chmod
-
dr--r----- 2 pcc039 pcc 4096 1월 4 15:35 forAll
- d로 시작함 -> directory
- directory의 소유자는 pcc라는 그룹에 속해있는 pcc039
- 소유자는 directory를 read 할 수 있는 권한을 가짐
- 그룹원들은 directory를 read 할 수 있는 권한을 가짐
- 다른 사람들은 directory를 read, write, execute 할 수 있는 권한을 가지지 않음
- d/rwx/rwx/rwx
- 종류/소유자에게 부여된 권한/그룹원에게 부여된 권한/다른 사람들에게 부여된 권한
- rwx는 8진수 체계
- chmod 777을 사용하면 모든 사용자에게 모든 권한이 부여됨
- chmod 770의 경우에는 소유자와 그룹원들에게 모든 권한이 부여됨
- chmod 700의 경우에는 소유자에게만 권한이 부여됨
- w 권한을 막고 싶은 경우 5를 할당하는 방식
hello.c 파일 컴파일 (vi editor 사용법)
- vi hello.c
- vi 명령어를 이용해 hello.c 파일을 만듦
- vi editor로 변환됨
- Insert 키
- vi editor를 인서트 모드로 전환
#include <stdio.h>
int main()
{
printf("Hello World! \n");
}
- 삽입하고자 하는 문구를 입력 (c언어 문법에 맞게)
- esc
- esc키를 통해 인서트 모드에서 빠져나옴
- :wq
- :wq(저장 후 종료)를 입력하여 vi editor모드에서 빠져나옴
- cc hello.c
- hello.c 파일을 컴파일
- 같은 디렉토리에 a.out이라는 출력파일이 생성됨
- ./a.out
- 현재 디렉토리 아래의 a.out 파일을 실행시킴
- Hello World! 출력
Lecture 02 [2022.01.05]
Linux command
- echo
- 출력하고자 하는 문구를 출력
- wall
- 접속해있는 모든 사용자에게 원하는 문구를 출력
- write ~~(특정 사용자 id)
- ~~(특정 사용자)에게 원하는 문구를 출력
- mesg y/n
- 다른 사용자의 write 명령을 통해 나에게 보내지는 메세지를 차단하거나 허용할 수 있음
- man
- manual
- 명령어에 대한 정보를 제공함
- mv ~~ --
- --이 이미 존재하는 경우 ~~를 --로 이동시킴
- --이 존재하지 않는 경우 ~~의 이름을 --로 수정함
- cp ~~ --
- ~~를 --로 복사함
- more
- 한 페이지 이상의 출력 내용을 페이지 단위로 보여줌
- history
- 지금까지 사용한 명령어 리스트를 보여줌
- sleep ~~(초 단위의 시간)
- ~~초까지 모든 실행을 중단
- sleep ~~; 다른 명령어
- ~~초 이후에 다른 명령어를 실행함
- (sleep ~~; 다른 명령어) &
- ~~c초 이후에 다른 명령어를 실행하고 그 동안 다른 작업 가능
- 괄호 안의 작업을 background에서 실행
- diff ~~ --
- ~~ 파일과 -- 파일을 비교
- 일치하는 경우 메세지가 뜨지 않음
- 일치하지 않는 경우 다른 부분을 보여줌
- ctrl + c
- kill
- 현재 진행 중인 작업을 지움
- ctrl + d
- 현재 진행 중인 작업을 중단함
- ps
- 현재 진행 중인 process 확인
- ps -al의 경우 hidden file까지 확인 가능
- fg %(~~)
- background(백그라운드)에서 실행 중인 ~~를 foreground(포그라운드) 작업으로 전환
- strings
- 읽을 수 있는 데이터만 보여줌
- standard stream(표준 스트림)
- standard input(stdin, 표준 입력 스트림)
- 입력을 위한 스트림
- fd(File Descriptor, 파일 디스크립터) : 0 할당
- standard output(stdout, 표준 출력 스트림)
- 출력을 위한 스트림
- fd(File Descriptor, 파일 디스크립터) : 1 할당
- standard error(stderr, 표준 에러 스트림)
- 에러메세지 출력을 위한 스트림
- fd(File Descriptor, 파일 디스크립터) : 2 할당
- stream(스트림)
- 유닉스 계열 운영체제에서 프로그램과 주변 기기 사이에 미리 연결된 입출력 통로
- redirection(리다이렉션)
- '>' (표준 출력-덮어쓰기)
- 사용법 : 명령어 > 파일
- 명령어의 표준 출력 스트림 도착 지점을 파일로 설정
- '<' (표준 입력)
- 사용법 : 명령어 < 파일
- 파일로부터 입력 받음
- '>>' (표준 출력-추가)
- 사용법 : 명령어 >> 파일
- 명령어의 표준 출력 스트림 도착 지점 파일에 내용 추가
- | (pipe)
- 사용법 : A | B
- A command의 표준 출력을 B command의 표준 입력으로 사용
-
ls -al | grep root
- ls -al command의 출력 결과 중 "root"라는 문자를 포함하는 결과만 출력
Linux System
- stdio(표준입출력장치)
- shell에서 기본이 되는 input, output 장치
computer hardware system
- CPU
- Memory
- Storage Devices
- Input Devices
- Output Devices
- buffer
- 데이터를 전송하는 동안 일시적으로 데이터를 보관하는 메모리의 일종
- Input Devices에 관여하는 buffer는 inbuffer
- Output Devices에 관여하는 buffer는 outbuffer
- inbuffer와 outbuffer를 합쳐 iobuffer라고 함
Software
- System Software (SS : 시스템 소프트웨어)
- Operating System (OS : 운영체제)
- Compiler (컴파일러)
- Devices (디바이스)
- Application (APP : 애플리케이션)
Linux Software
- Hardware
- Linux : Kernel
- System Call : Interface
- System Utilities : cat, ls, date, ps, kill, who
- Linux Shell : bash
Linux Kernel SCI (System Call Interface)
- I/O sub system
-
Terminals
-
Character device driver
-
Sockets
-
Network protocols
-
Network device drivers
-
File systems
-
Block device drivers
-
- Memory management sub system
- Process management sub system
컴퓨터 구성 요소
- Users (사용자)
- Hardware (하드웨어)
- Software (소프트웨어)
- Data (데이터)
파일 종류
- d~ : directory
- c~ : character device
- b~ : block device
- l~ : link
Lecture 03 [2022.01.06]
프롬프트 색상 변환
cp ~hwan/.profile ~hwan/.bashrc ~hwan/.bash_logout ~
source .profile
교수님 코드를 카피하여 프롬프트의 색상을 바꿈
linux command
- grep
- 찾고자 하는 텍스트를 입력하면 텍스트가 들어간 line을 출력함
- grep 텍스트 파일명
- 파일 내부에서 텍스트 찾기
- grep 텍스트
- standard input을 받고 입력된 텍스트 중에서 원하는 텍스트가 있을 경우 standard output을 출력
- which
- 찾고자하는 파일의 위치에 대한 정보 제공
- tee
- standard input(표준 입력)에서 읽어서 standard output(표준 출력)과 파일에 쓰는 명령어
-
echo "hello" | tee a.txt
- 명령을 실행하면 a.txt 파일과 터미널에 hello가 출력됨
git command
- git clone
- 저장소 복제
- window에서는 git Bash, macOS나 Linux에서는 터미널을 사용
- git pull
- 원격 저장소에서 로컬 저장소로 소스를 가져오는 명령어
- 실습에서는 git.ajou.ac.kr의 소스를 git Bash로 가져올 때 사용
- git commit
- 의미있는 변화에 대해 기록
- vi editor 모드로 바뀜
- vi editor 모드로의 변환을 원하지 않으면 git commit -m
- vi editor 모드에서 Insert 키를 누른 뒤 입력하고자 하는 commit 내용을 작성
- git push
- 현재 프로젝트에서 커밋(commit)된 내용을 원격 저장소로 내보냄
- 실습에서는 git Bash에서 수정된 내용을 git.ajou.ac.kr로 내보낼 때 사용
- git add
- 다음 변경을 기록(commit)하기 전 변경하고자 하는 것들을 모아두기 위해 사용
- git config
- commit을 누가 작성했는지 표시하기 위해 username과 email을 설정해야 함
- 설정하는 방법
git config --global user.name "KimNayoung" git config --global user.email "skdud1201@ajou.ac.kr"
- 삭제하는 방법
git config --unset --global user.name git config --unset --global user.email
- config 리스트 확인
git config --list
- git mv
- git에 있는 파일의 이름을 변경
- git rm
- git 저장소와 로컬 디렉토리에서 파일을 삭제
markdown
- #을 통해 제목을 설정
- #/##/###/####/#####/###### 6단까지 가능
- *를 통해 리스트를 설정
- Tab키를 통해 구분
- <> 괄호 안에 br을 넣으면 줄 구분 가능
- 1.을 통해 텍스트에 번호를 매길 수 있음
- Tab키를 누르면 다른 리스트로 분류되어 숫자가 리카운트됨
- 번호를 매기지 않고 "1."이라고 입력하기를 원한다면 1.로 입력함
-
BOLD
- ** ** 사이에 텍스트를 입력하면 텍스트를 볼드처리할 수 있음
-
ITALIC
- 이탤릭체로의 변환을 위해서는 * * 사이에 텍스트를 입력
-
BOLD ITALIC
- *** *** 사이에 텍스트를 입력하면 텍스트를 볼드 이탤릭체로 바꿀 수 있음
- 글자 끝에 #를 삽입하면 줄 구분이 가능
- `을 소스코드의 시작과 끝에 세번씩 쓰면 소스코드를 입력할 수 있음
Lecture 04 [2022.01.10]
Linux command
-
sh
- 새로운 shell을 여는 명령어
- ps -l을 통해 PPID를 비교해보면 새로 생성된 sh이 bash에서 실행된 shell이라는 것을 확인할 수 있음
- exit, ctrl + d, logout 명령어를 통해 shell에서 나갈 수 있음
-
;
- 한 줄에서 여러 개의 명령 실행 가능
-
a.out <<< 0 ; a.out <<< 999 ; a.out <<< -100
- a.out 출력 파일에 0, 999, -100을 넣은 출력 값을 전부 보여줌
-
<< (명령 종료할 때 입력할 문자)
-
cat << QQQ
- QQQ를 입력하면 cat 명령이 종료됨
-
-
$(명령)
- 명령을 실행한 값
-
cat <<< $(echo "hello")
- echo "hello" 명령을 실행한 결과값 hello를 cat명령의 stdin으로 연결하여 실행함
-
cc -o (실행파일 이름) (컴파일할 파일 이름)
- 컴파일 명령(cc)를 실행할 때 실행 파일 이름을 지정하고 싶은 경우 cc -o 명령을 이용함
Command
- flush
- 현재 buffer에 있는 모든 값들을 지우는 명령어
- stdout 실행과 stderr 실행 사이의 우선 순위를 정해주고 싶은 경우 flush 명령을 통해 buffer를 비워줌으로써 해결함
Python Command
- Git Bash에서 python이라고 치면 파이썬 실행 가능
- python에서 나가고자 할 때는 ctrl + d 또는 exit() 입력
- bin(10진수)
- 10진수 수를 2진수로 바꿔주는 명령어
Standard IO stream
- stdin buffer, stdout buffer, stderr buffer는 memory에 저장되어 있음
Understanding redirection
- < 0< << 0<< > 1> >> 1>> 2> 2>>
- redirection의 위치는 신경쓰지 않아도 됨
-
echo hello > ./out.txt
-
echo > ./out.txt hello
와 결과가 동일함 - hello를 현재 디렉토리 아래에 있는 out.txt파일에 저장
-
-
echo hello >&2
-
echo >&2 hello
와 결과 동일 - stdout과 stderr을 모두 내보냄
-
-
read -r line < file
< file read -r line
- file의 한 줄을 읽음
- https://mug896.github.io/bash-shell/redirections.html
- 추가
a.out <<< 300 > out.txt // Hello stderr 300 출력
cat out.txt // Hello stdout 300 출력
a.out 출력파일에 300을 stdin으로 넣고 stdout을 out.txt파일로 보냄 남은 출력값인 stderr이 위 명령에 대한 출력으로 실행되고 cat 명령을 통해 out.txt 파일을 실행하면 이전에 보내진 stdout 값이 출력
Here document, Here strings
- 0<< or <<
- 임시 파일을 만들어 stdin으로 연결
- <<< (bash에서만 존재)
- string을 stdin 입력으로 연결
- globbing이 발생하지 않음
-
a.out <<< 99
- a.out 출력파일을 실행할 때 입력하는 값을 <<< 뒤에 넣어서 한 줄로 실행 가능
Pipe
-
cmd1 | cmd2
- cmd1과 cmd2는 동시에 병렬로 실행
- cmd1이 cmd2보다 빠르면 write은 파이프에 블록되고 더이상 진행되지 않음
- cmd2가 cmd1 보다 빠르면 파이프로부터의 read는 블록
- cmd1이 먼저 종료하면 파이프는 close 되고 cmd2는 End-Of-File 로 인식해 종료
- cmd2가 먼저 종료하면 파이프는 close 되고 cmd1은 다음번 write에 SIGPIPE 신호를 받고 종료
Glob (글로브)
- glob 패턴은 와일드카드 문자로 여러 파일 이름의 집합을 지정
-
mv *.txt textfiles/
- .txt로 끝나는 모든 파일을 textfiles 디렉토리로 이동
- *은 모든 문자열을 가리키는 와일드 카드
- *.txt는 글로브 패턴
- 일반적인 와일드카드로는 *,?,[…]등이 있음
Explain code function
int ifuncAdd(int a, int b)
{
return a+b;
}
- 함수명 : ifuncAdd
- 매개변수(parameter) : a, b (int 형)
- 정수 형태의 a와 b를 받아서 더한 값을 return하는 함수
- 수학적 의미의 정수는 아님
- 수학적 의미의 정수 범위는 -무한대 ~ 무한대. 그러나 코드에서의 a와 b는 무한대 범위의 수를 표현할 수 없음
- 따라서 '정수형'이라고 표현 -> 진짜 정수는 아님!
Type Basic
- Standard signed integer type
- signed char, short int, int, long int, long long int
- Unsigned
- unsigned ...
- floating type
- float, double, (long double)
- Definition in standard
- char - large enough to store any execution character set
- floating - The set of values of the type float is a subset of the set of values of the type double; the set of values of the type double is a subset of the set of values of the type long double.
- _Complex
- _Bool - can store 0,1
Negative integer
- the corresponding value with sign bit 0 is negated (sign and magnitude)
- the sign bit has the value - (2M) (two's complement)
- 1의 보수를 구한 후 가장 낮은 비트에 +1
- the sign bit has the value - (2M-1) (one's complement)
Memory Model
- Automatic
- Static
- Manual
- Const
binary code
#include <stdio.h>
int main() {
int i;
int in_a;
fscanf(stdin, "%d", &in_a);
for (i = 31; i >= 0; i--) {
fprintf(stdout, "%d", ((in_a >> i) & 1));
if (i % 4 == 0) {
fprintf(stdout, " ");
}
}
fprintf(stdout, "\n");
}
- int 형으로 in_a를 입력받고 shift 연산을 한 후 1과 & operation을 하여 2진수로 변환하는 코드
- '>>' (right shift) = /2
- '<<' (left shift) = *2
& operation
-
100 & 255
- 100 출력
- 255를 2진수로 변환하면 1111 1111이 되기 때문에 어떤 수 A와 & operation을 하면 항상 A가 출력됨
-
100 & -1
- 100 출력
- -1을 2의 보수를 통해 2진수로 변환하면 모든 비트가 1로 채워져있기 때문에 100이 출력됨
shift
- signed int
int in_a, in_b;
fscanf(stdint, "%d", &in_a);
in_b = in_a >> 2;
shift 연산 이후 비어있는 비트에 0이 채워짐
- unsigned int
unsigned int in_a, in_b;
fscanf(stdint, "%d", &in_a);
in_b = in_a >> 2;
shift 연산 이후 비어있는 비트에 1이 채워짐
Lecture 05 [1.11]
Linux Command
-
ln 옵션 원본파일 대상파일(대상 디렉토리)
- ln은 link의 약어로서 리눅스 파일시스템에서 링크 파일을 만드는 명령어
- 리눅스에서는 심볼릭링크(소프트링크)와 하드링크의 두가지 링크 파일이 존재하는
- Symbolic link
ln -s 원본파일 대상파일
- 단순히 원본파일을 가리키도록 링크만 시켜둔 것
- 원본파일을 가리키고만 있으므로 원본 파일의 크기와는 무관
- 경로의 글씨 수가 파일의 크기가 됨
- 원본 파일이 삭제되어 존재하지 않는 경우, 링크파일이 깜박이며 원본 파일이 없다는 것을 알려줌
- Hard Link
ln 원본파일 대상파일
- 원본 파일과 다른 이름으로 존재하는 동일한 파일
- 원본 파일과 동일한 내용의 다른 파일
- 둘 중 하나가 삭제되더라도 나머지 하나는 그대로 존재
- 원본 파일의 내용이 변경될 경우 링크파일의 내용 또한 자동으로 변경
- 옵션
- --backup(=CONTROL) : 대상파일이 이미 존재할 경우에 백업파일을 만든 후에 링크파일 생성
- -b : 링크파일 생성시에 대상파일이 이미 존재하면 백업파일을 만든 후에 링크파일을 생성
- -d : 디렉토리에 대한 하드링크파일생성을 가능하게 함. 단 root 권한으로 수행하더라도 시스템의 권한제한으로 인하여 실패할 가능성이 높음. (-F 와 --directory 는 -d 와 동일함)
- -f : 대상파일이 존재할 경우에 대상파일을 지우고 링크파일을 생성
- -i : 대상파일이 존재할 경우에 대상파일을 지울것인가를 확인요청 (--interactive 와 동일)
- -s : 심볼릭 링크파일을 생성
- -S : 백업파일 생성시에 원하는 접미사(suffix)를 지정할 수 있음
- -t, --target-directory=DIRECTORY : 링크파일을 생성할 디렉토리를 지정
-
cc -Wall 파일이름
- 파일을 컴파일할 때 모든 부분에 대해서 경고가 필요한 부분에 warning 메세지를 띄움
vi Command
-
dd
- 한 줄 잘라내기
-
yy
- 한 줄 복사
-
p
- 붙여넣기
-
yw
- 한 단어 복사
c preprocessor (cpp, C 전처리기)
- 컴파일 전에 C 프로그램을 수정하는 매크로 프로세서
- 원본 파일을 처리하는 동안 전처리기는 헤더 파일과 매크로를 정의된 파일과 값으로 바꿈
- 즉, #으로 시작하는 line은 실제 컴파일이 시작되기 전에 처리
- 전처리가 끝난 코드는 추가 작업을 위해 컴파일러로 전송
- 작업 종류
- 헤더 파일 추가
-
#include <stdio.h>
소스 코드에서 #include 문을 제거하고 stdio.h 파일 내용을 소스 프로그램에 포함
- 매크로 확장
-
#define PI 3.14
컴파일이 시작되기 전에 전처리기가 프로그램 전체에서 PI 변수를 3.14로 변환
- 조건부 컴파일
-
#if..., #ifdef..., #ifndef..., #error
특별한 전처리 지시어를 사용하여 다양한 조건에 따라 프로그램의 일부 포함 혹은 제외 가능
- 라인 컨트롤
-
#line
프로그램을 사용하여 소스 파일을 중간 파일로 결합하거나 재배열한 다음 컴파일 하는 경우, 각 소스 라인이 어디서 왔는지 컴파일러에 알릴 수 있음
x86_64 의미
- x86 : CPU 종류 -> intel CPU
- 64 : 64비트
signed & unsigned
- signed
- %d를 이용해서 출력
- 정수형 변수 중 부호를 갖는 변수를 선언
- signed int 범위 : –2,147,483,648 ~ 2,147,483,647
- signed char 범위 : -128 ~ 127
- unsigned
- %u를 이용해서 출력
- 부호 비트를 제거해 저장 가능한 양수 범위를 두배로 늘림
- 음수를 사용하지 않겠다는 의미로 부호 비트가 필요없음
- unsigned int 범위 : 0 ~ 4,294,967,295
- unsigned char 범위 : 0 ~ 255
Count number of 1 (binary)
#include <stdio.h>
int count_one(int in_a)
{
int i, count = 0;
for(i = 31; i>=0; i--)
{
if((in_a>>i) & 1)
count++;
// count += (in_a>>i)&1; 위의 if문 대체 가능
}
return count;
}
int main()
{
int i;
unsigned int in_a;
fscanf(stdin, "%u", &in_a);
fprintf(stdout, "%u \t: ", in_a);
for(i=31; i>=0; i--)
{
fprintf(stdout, "%d", ((in_a>>i) & 1));
if(i % 4==0)
{
fprintf(stdout, " ");
}
}
fprintf(stdout,": %d \n", count_one(in_a));
}
이전 Lecture 05에 있는 binary code 참고 count_one 함수에 입력받은 in_a를 전달하여 2진수 형태로 바꾸고 count += (in_a>>i)&1 연산을 통해 1의 개수를 구한 후 return
int count_one(int in_a)
{
int i=32, count = 0;
while (i>0)
{
count += (in_a>>i) & 1;
i--;
}
return count;
}
코드 실행을 빠르게 하기 위해 위와 같이 코드 수정 가능 if문은 실행이 오래 걸림
C Operator Precedence
The basic memory model in C
- Automatic(동적변수)
- 처음 사용할 때 변수 선언
- 범위를 벗어날 때 제거됨
- Static(정적변수)
- 프로그램이 실행되는 동안 같은 장소에 존재
- 배열 크기는 고정되지만, 값은 변경 가능
- 주 작업이 시작되기 전 데이터가 초기화되므로 상수를 사용하여 초기화해야 함
- 정적 키워드를 사용하여 함수 외부에 선언된 변수 및 내부 함수는 정적임
- 정적 변수를 초기화하지 않으면 0(또는 Null)으로 초기화
- Manual
- 타입의 종류는 malloc과 free
- 선언 후 배열 크기를 조정할 수 있는 유일한 메모리 유형
Question
double (*f[10])(int const *a, double (*g[10])(double h));
- 함수 명이 f인 함수 선언
- 함수는 double을 return
- 함수 f는 크기가 10인 포인터의 array
- 첫번째 매개변수는 int const 형태의 포인터 a
- 두번째 매개변수
- 함수 명이 g이며 크기가 10인 포인터의 array
- double을 return
- double을 리턴하는 상수 h를 매개변수로 가짐
Static
int static_check(int a)
{
int static numCalls = 0;
fprintf(stderr, "Call : %d\n", numCalls);
numCalls++;
}
int main()
{
int num;
fscanf(stdin, "%d", &num);
static_check(num);
static_check(num);
static_check(num);
static_check(num);
static_check(num);
}
- static으로 선언된 변수는 main 함수의 시스템이 끝까지 돌아갈 때까지 초기화되지 않음
- 따라서 위 코드의 출력 값은
Call : 0
Call : 1
Call : 2
Call : 3
Call : 4
그러나 static이 아닌 int형으로 선언하면 static_check함수가 선언될 때마다 numCalls 변수가 0으로 초기화 됨
int static_check(int a)
{
int numCalls = 0;
fprintf(stderr, "Call : %d\n", numCalls);
numCalls++;
}
int main()
{
int num;
fscanf(stdin, "%d", &num);
static_check(num);
static_check(num);
static_check(num);
static_check(num);
static_check(num);
}
- 위 코드의 출력 값은
Call : 0
Call : 0
Call : 0
Call : 0
Call : 0
-
int static numCalls;
위 코드와 같이 초기화하고자 하는 값을 입력하지 않으면 static의 경우 자동으로 0으로 초기화됨 0으로 초기화되는 것을 원하지 않는 경우int static numCalls = 100
과 같이 초기화함 -
automatic variable의 경우 초기화 없이 값을 출력하는 명령을 실행할 경우 랜덤 값이 출력됨
const & define
- const
- 메모리가 할당됨
- 주소를 직접 건드리면 const의 값 또한 변경 가능
- 상수화가 되어 read only로 변환 -> 주로 라이브러리에서 사용
- 타입을 함께 선언하여 #define에 비해 표현 범위와 구조에 대해 명확함
- define
- 컴파일 전처리단계에서 글자를 치환해주는 방식
Lecture 06 [2022.01.12]
Linux Command
-
clear
- 터미널 내용 지우기
-
alias
- 자주 사용하는 긴 명령어 조합을 간단하게 등록해놓을 수 있는 명령어
alias 별칭='명령어'
- 별칭을 삭제하기 위해서는 unalias 명령을 이용
- alias -p를 통해 등록된 단축어 확인 가능
- unalias -a는 모든 alias 설정을 삭제
- 설정된 alias를 사용하고 싶지 않은 경우 명령어 앞에 \를 붙여서 사용
- logout된 상태에서도 alias 단축어를 사용하고 싶은 경우
-
h
- alias로 지정된 history의 단축어
-
!$
- 가장 최근 명령의 마지막 파라미터를 쓰고 싶은 경우 사용
-
kill
- 다른 터미널에 떠있는 프로세스를 kill하는 명령어
- 터미널의 프로세스를 확인하는 명령어는 ps
-
cc && a.out
- 컴파일 후 문제가 없을 경우 a.out을 실행
-
cc ; a.out
- 컴파일 후 a.out을 실행
- 이때 컴파일 에러가 발생하면 가장 최근에 컴파일 성공한 a.out의 결과를 출력
-
cc || echo "Error"
- 컴파일 에러가 날 경우 echo의 결과를 출력
vi Command
-
o
- 현재 위치 다음 줄에 insert 모드로 문구를 삽입하고 싶은 경우
-
O
- 현재 위치 윗 줄에 insert 모드로 문구를 삽입하고 싶은 경우
Pointer Basic
- operation
- &val - Address of val (val의 주소)
- a & b - bitwise and (& 연산) // 헷갈리지않기
- %lld로 받음
- *ptr - Value in address val (val의 주소의 값)
- &val - Address of val (val의 주소)
- increment
- int *a; // 64 bits 컴퓨터에서 일반적으로 4 bites
- long long *b // 64 bits 컴퓨터에서 일반적으로 8 bites
- void *c // 64 bits 컴퓨터에서 일반적으로 1 bites
- 기본적으로 char *c와 똑같음
operation code
#include <stdio.h>
int main()
{
int a = 100;
int b = 200;
fprintf(stdout, "%d : %d\n", a, &a);
fprintf(stdout, "%d : %d\n", b, &b);
}
코드를 실행하면 &a와 &b의 값 차이가 4인 것을 확인할 수 있음 -> 랜덤으로 출력되는 값이 아니라는 의미 음수로 출력되는 경우 = 값을 출력하는 과정에서 오버플로우가 생김 -> %lld를 통해 출력함
64비트 컴퓨터~~에서 64비트의 의미
- 한번에 처리 가능한 데이터의 크기
- Address line의 크기
code
#include <stdio.h>
void add(int *a, int *b, int *c)
{
*c = *a + *b;
}
int main()
{
const int a = 100;
int b = 200;
const int c = 999;
fprintf(stdout, "%d : %lld\n", a, &a);
fprintf(stdout, "%d : %lld\n", b, &b);
add(&a,&b,&c); //1
c = a+b; //2
fprintf(stdout, "%d : %lld\n", c, &c);
int d=999;
fprintf(stdout, "%d :%lld %lld\n", d, ((void *)(&d))+1, &d+1);
}
- c가 const int로 선언되어 있기 때문에 1의 방법으로 c의 값을 수정할 수 있음
- 방법 1 : 새로운 함수 add를 선언하여 매개변수로 a, b, c의 주소를 넣고 그 값을 계산하여 c를 수정
- 방법 2 : main 함수 내부에서 a와 b를 더해 c를 수정 -> 오류가 생김
- 기존 int 자료형이었던 d의 주소값을 void로 선언함으로써 메모리 크기를 4에서 1로 바꿈
- &d+1의 경우 기존 int형으로 선언된 경우에는 4가 증가하지만 void형에서는 1이 증가
- 컴파일 후 실행할 때마다 주소 값 바뀜
int an_array[ ] vs int *a_pointer
- int an_array[32];
- 4 bytes 메모리 32개 존재
- Program will do;
- set aside a space on the stack big enough for 32 integers, and
- declare that an_array is a pointer, and
- bind that pointer to point to the newly allocated space.
- int *a_pointer
- Just pointer;
- a_pointer = malloc(32*4);
array pointer code
#include <stdio.h>
int sumArray3(int a[3], int sum)
{
sum = *a;
a++;
sum += *a;
a++;
sum += *a;
fprintf(stdout, "%d : %lld %llx\n", sum, &sum, &sum);
return a[3];
}
int main()
{
int a = 100;
int b = 200;
int c = 999;
int arr[4] = {100,200,300,400};
int *parr;
parr = arr;
parr++;
fprintf(stdout, "%d : %lld %lld\n", *parr, parr, arr);
c = sumArray3(arr, b);
fprintf(stdout, "%d : %lld %llx\n", b, &b, &b);
fprintf(stdout, "%d : %lld %llx\n", *arr, *arr, *arr);
fprintf(stdout, "%d : %lld %llx\n", &arr, &arr, &arr);
fprintf(stdout, "%d : %lld %llx\n", arr[2], &arr[2], &arr[2]);
fprintf(stdout, "%d : %lld %llx\n", arr[3], &arr[3], &arr[3]);
fprintf(stdout, "%d : %lld %llx\n", arr[4], &arr[4], &arr[4]);
fprintf(stdout, "%d : %lld %llx\n", arr[4000], &arr[4000], &arr[4000]);
}
- arr 배열을 선언하여 출력
- arr과 &arr을 %lld로 출력하면 같은 값을 가지며 arr, arr[2], arr[4]가 각각 8씩 차이나는 것을 보아 arr은 arr[0]을 의미
- 배열 역시 int로 선언되는 경우 메모리 값이 4씩 차이남
- 배열의 크기가 4(0~3)임에도 arr[4]의 메모리 값이 출력됨
- 배열 arr을 const로 선언하여 arr++; 과 같이 직접적으로 arr의 값을 바꾸려고 하면 에러 발생
- 따라서 int *parr;과 같이 포인터를 따로 선언하여 사용해야 함
- arr[4000]에 대한 값을 출력하려고 하면 에러가 발생함
- 배정된 메모리 용량을 넘어서는 범위이기 때문
Pointer / Address
- int const A constant integer
- int const * A (variable) pointer to a constant integer
- int * const A constant pointer to a (variable) integer
- int * const * A pointer to a constant pointer to an integer
- int const * * A pointer to a pointer to a constant integer
- int const * const * A pointer to a constant pointer to a constant integer
Call by Address(Reference) vs Call by Value
#include <stdio.h>
void addPointer(int *a, int *b, int *c) // Call by Address
{
*c = *a + *b;
fprintf(stdout, "In addPointer A %d : %lld %llx\n", *a, a, a);
fprintf(stdout, "In addPointer B %d : %lld %llx\n", *b, b, b);
fprintf(stdout, "In addPointer C %d : %lld %llx\n", *c, c, c);
*a = -100;
*b = -200;
}
int addValue(int a, int b, int c) // Call by Value
{
c = a + b;
fprintf(stdout, "In addValue A %d : %lld %llx\n", a, &a, &a);
fprintf(stdout, "In addValue B %d : %lld %llx\n", b, &b, &b);
fprintf(stdout, "In addValue C %d : %lld %llx\n", c, &c, &c);
a = 999; b=888;
return c;
}
int main()
{
int a = 100;
int b = 200;
int c = 999;
fprintf(stdout, "%d : %lld %llx\n", a, &a, &a);
fprintf(stdout, "%d : %lld %llx\n", b, &b, &b);
addPointer(&a,&b,&c);
fprintf(stdout, "%d : %lld %llx\n", c, &c, &c);
// a = 200; b = 300;
c = addValue(a,b,c);
fprintf(stdout, "%d : %lld %llx\n", a, &a, &a);
fprintf(stdout, "%d : %lld %llx\n", b, &b, &b);
fprintf(stdout, "%d : %lld %llx\n", c, &c, &c);
}
실행 결과
100 : 140732089039420 7ffebe2cfa3c
200 : 140732089039424 7ffebe2cfa40
In addPointer A 100 : 140732089039420 7ffebe2cfa3c
In addPointer B 200 : 140732089039424 7ffebe2cfa40
In addPointer C 300 : 140732089039428 7ffebe2cfa44
300 : 140732089039428 7ffebe2cfa44
In addValue A -100 : 140732089039388 7ffebe2cfa1c
In addValue B -200 : 140732089039384 7ffebe2cfa18
In addValue C -300 : 140732089039380 7ffebe2cfa14
-100 : 140732089039420 7ffebe2cfa3c
-200 : 140732089039424 7ffebe2cfa40
-300 : 140732089039428 7ffebe2cfa44
- main 함수에서 변수 a, b, c에 대한 메모리가 할당됨
- 메모리 주소는
- a : 140732089039420
- b : 140732089039424
- c : 140732089039428
-
addPointer(&a,&b,&c);
- addPointer 함수에 a, b, c의 메모리 주소값을 매개변수로 넣고 실행
- Call by Address 형태의 함수에서는 main 함수의 메모리에 대해 수정 가능 -> a, b값이 -100, -200으로 바뀜
- 여전히 c는 300
-
c = addValue(a,b,c);
- addValue 함수에 위에서 바뀐 값 a = -100, b = -200을 넣고 실행
- Call by Value 형태의 함수에서 수정된 값은 main 함수의 메모리에 저장되지 않음
- 함수 내부에서 a, b, c의 메모리 주소를 출력하면
- a : 140732089039388
- b : 140732089039384
- c : 140732089039380
- 연산 후 c = -300
- 함수를 int형으로 선언하고 return c; 를 통해 c 값(-300)을 메인 함수로 리턴하여 c = addValue(a,b,c); 에서 메인함수의 변수 c에 값을 저장
Lecture 07 [2022.01.13]
Linux Command
-
cp (복사하고자 하는 파일의 경로) (바꿀 파일의 이름)
- 파일을 복사할 때 파일의 이름을 바꿔서 복사할 수 있음
-
od
- 바이너리 파일을 8진수로 dump하는 명령어
- 바이너리 파일의 내용을 읽을 수 있음
- od -x : 16진수로 dump
- 가장 왼쪽에 출력되는 7자리 수는 주소를 나타냄
-
gcc(GNU Compiler Collection)
- -o : 실행 파일 이름 바꾸기
- -c : .o 파일 생성 (assembly)
- -E : .c 파일 생성
- -O : 최적화
- -S : 전처리된 파일을 어셈블리 파일로 컴파일하고 멈춤 (.s 파일 생성)
- --32, --64 : 32비트 컴파일(64비트 컴퓨터에서도 컴파일 가능), 64비트 컴파일
- -Dmacro : #define 가능
Noun-Adjective Form
- 코드는 위의 Pointer / Address 참고
- 수식하고자 하는 문자-수식어 순으로 작성함
const int a = 100;
int *p = &a;
fprintf(stdout, "a : %d\n", a); // 100
*p = 200;
fprintf(stdout, "a : %d\n", a); // 200
코드를 실행하면 a를 const로 선언했음에도 불구하고 a의 값이 변경가능하다는 것을 확인할 수 있음 그럼에도 불구하고 const로 선언하는 이유는
- 에러가 생기게 함으로써 경고
함수의 포인터
-
void fp();
- void : 리턴하는 값을 알려줌
fnpointer 코드
#include <stdio.h>
#define FN_ADD 0
#define FN_SUB 1
#define FN_MUL 2
#define FN_DIV 3
#define FN_ERR 4
void add(int *a, int *b, int *c)
{ *c = *a + *b; }
void sub(int *a, int *b, int *c)
{ *c = *a - *b; }
void mul(int *a, int *b, int *c)
{ *c = (*a) * (*b); }
void div(int *a, int *b, int *c)
{ *c = (*a) / (*b); }
int main()
{
int a, b, c;
char ch;
int op = FN_ERR; // default is err
scanf("%d %c %d", &a, &ch, &b);
void (*fp[4])(int *, int *, int *) = {add, sub, mul, div};
switch (ch)
{
case '+':
op = FN_ADD;
break;
case '-':
op = FN_SUB;
break;
case '*':
op = FN_MUL;
break;
case '/':
op = FN_DIV;
break;
default :
op = FN_ERR;
break;
}
fp[op](&a,&b,&c);
if(op == 4){
fprintf(stdout, "wrong input\n");
return 0;
}
fprintf(stdout, "%d \n", c);
}
수정 코드 설명
- '#define'을 지정하여 실수를 줄임
- 잘못된 부호를 입력한 경우 -> wrong input 출력
C Compile and Executive
-
preprocessor 명령이 가장 먼저 실행
- c언어에서는 주로 #으로 시작
-
user의 소스코드 컴파일
- preprocessor 명령이 실행된 상태
- assembly를 생성
- 프로그래밍 언어를 기계어로 바꾸는 과정
- Interpreter : 한 줄씩 컴파일 (대표적으로 파이썬)
- Compiler : 소스코드를 한 번에 컴파일 (대표적으로 C언어)
-
Link
- scanf와 printf를 연결하는 등의 과정
- linking 이후에 generate executable code를 만듦
- dynamic link와 static link로 구분
-
Loader
- a.out 실행파일을 실행할때 loading이 일어남
-
이러한 단계를 확인하는 명령어 : gcc
#define vs const
- #define
- preprocessor
- const
- 표현 범위와 구조에 대해 명확하게 표현
- 메모리 할당 -> 주소로 접근하면 const 값 변경 가능
조건부 컴파일
-
정해진 조건에 따라 소스 코드의 컴파일 여부를 제어하는 전처리기
-
#define으로 매크로의 이름을 정의
-
'DATE',' TIME', 'FILE', 'LINE'는 컴파일러에서 제공하는 매크로
- 'DATE': 컴파일한 날짜(실행 시점의 현재 날짜가 아님)
- 'TIME': 컴파일한 시간(실행 시점의 현재 시간이 아님)
- 'FILE': 'FILE' 매크로가 사용된 헤더, 소스 파일
- 'LINE': 'LINE' 매크로가 사용된 줄 번호
-
#ifdef와 #endif 지시자를 사용하여 정의
#ifdef 매크로 // 매크로가 정의되어 있다면 #ifdef, #endif 사이의 코드를 컴파일
코드
#endif
- #ifndef와 #endif 지시자를 사용하여 정의
#ifndef 매크로 // 매크로가 정의되어 있지 않다면 #ifndef, #endif 사이의 코드를 컴파일
코드
#endif
#include <stdio.h>
#define DEBUG
int main() {
#ifdef DEBUG // #ifdef는 위에서 매크로가 선언된 경우 내부 코드가 실행됨
printf("Debug : %s \t %s \t %s \t %d \n", __DATE__, __TIME__, __FILE__, __LINE__);
#endif
char name[] = "Nayoung";
int age = 21;
#ifndef INTRO // #ifndef는 위에서 매크로가 선언되지 않은 경우 내부 코드를 실행함
printf("Name : %s \t Age : %d \n", name, age);
#endif
return 0;
}
코드에 #define INTRO를 추가하면 #ifndef 내부 코드는 실행되지 않음
- 값 또는 식 판별 후 조건부 컴파일
#if 값 또는 식
코드
#endif
#include <stdio.h>
#define DEBUG_LEVEL 2
int main()
{
#if DEBUG_LEVEL >= 2 // DEBUG_LEVEL이 2보다 크거나 같으면 #if, #endif 사이의 코드를 컴파일
printf("Debug Level 2 \n");
#endif
#if 1 // 조건이 항상 참이므로 내부 코드 컴파일
printf("It is 1 \n");
#endif
#if 0 // 조건이 항상 거짓이므로 내부 코드 컴파일하지 않음
printf("It is 0 \n");
#endif
return 0;
}
- defined
#if (defined DEBUG || defined TEST) && !defined (VERSION_10)
// DEBUG 또는 TEST가 정의되어 있으면서 VERSION_10이 정의되어 있지 않을 때
#include
- 전처리기
- 헤더 파일(.h)과 소스 파일(.c)를 포함
#include <파일>
#include "파일"
- <>
- C언어 표준 라이브러리의 헤더 파일을 포함할 때 사용
- " "
- 현재 소스 파일을 기준으로 헤더 파일을 포함
- 헤더 파일을 찾지 못할 경우 컴파일 옵션에서 지정한 헤더 파일 경로를 따름
extern
- 다른 소스 파일의 전역 변수를 사용할 수 있음
CPP - include file
- #include file as text
- #include <stdio.h> or "file.h"
- gcc Option - I
- Include location - ./usr/include/
- Default include location
- Prevent multiple include
- #pragma once (로딩 한번만)
#ifndef _MATH_
#include <math.h>
#endif
Lecture 08 [2022.01.17]
Linux Command
- ^(위 명령에서 잘못 입력한 문자)^ (바꿀 문자)
- 위 명령에서 특정 문자를 잘못 입력한 경우 사용함
.o file
GCC Optimization
- -O0(기본값)
- 최적화 수행 안 함
- -O, -O1
- 만들어지는 .o, .out 파일을 가능한 작게 하면서 컴파일 시간이 오래걸리지 않는 범위에서 최적화 수행
- -O2
- 만들어지는 코드가 가능한 빠르게 수행되지만 코드의 크기가 너무 커지지않는 범위에서 최적화 수행
- -O3
inline 반환값자료형 함수이름(매개변수자료형 매개변수이름)
{
}
#include <stdio.h>
inline int add(int a, int b)
{
return a+b;
}
int main()
{
int num1;
/*
num1 = inline int add(10, 20)
{
return 10 + 20;
}
*/
// 주석 부분을 컴파일러가 함수를 복제해서 넣어줌!
printf("%d", num1);
}
#error
#error 토큰 문자열
- 컴파일 시간에 사용자 지정 오류 메시지를 내보낸 다음 컴파일을 종료
- 프로그램 불일치나 제한된 내용에 접근하는 경우 개발자에게 고치도록 알림
- 명확한 에러 설명 혹은 프로그램의 안전성을 위해 사용
Token stringification (토큰 문자열화)
#define str(s) #s
str(p = "foo\n";) // outputs "p = \"foo\n\";"
str(\n) // outputs "\n"
#define xstr(s) str(s)
#define str(s) #s
#define foo 4
str (foo) // outputs "foo"
xstr (foo) // outputs "4"
- #define #s을 통해 문자열로 바꿔줌
- 항상 #s일 필요는 없음 str(문자) 내부의 문자와 동일
- 출력 형태를 다양하게 하는 매크로를 만들 때 유용 (%c, %d, %s 등)
- 토큰
- 프로그램을 구성하고 있는 문법적으로 의미 있는 최소 단위
Token Concatenation (토큰 붙여넣기)
#define DECLARE_STURCT_TYPE(name) typedef struct name##_s name##_t
DECLARE_STRUCT_TYPE(g_object);
// Outputs: typedef struct
g_object_s g_object_t;
//다른 예제
#include <stdio.h>
#define paster( n ) printf( "token" #n " = %d", token##n )
int token9 = 9;
int main()
{
paster(9); // output : token9 = 9
}
Macro Definition (2)
- Multiple lines
- 여러 줄 define 하고 싶을 때
#define NUMBERS 1, \
2, \
3
int x[] = { NUMBERS };
//int x[] = {1,2,3};
- Define Where?
foo = X;
#define X 4
bar = X; // foo = X and bar = 4
#define TABLESIZE BUFSIZE
#define BUFSIZE 1024
// TABLESIZE == BUFSIZE ==1024
#define BUFSIZE 1020
#define TABLESIZE BUFSIZE
#undef BUFSIZE
#define BUFSIZE 37 // TABLESIZE = 37
Macro Definition (3) - Function like Macro
- if문 보다 성능이 좋음
#define min (X, Y) ((X) < (Y) ? (X) : (Y))
x = min(a,b); -> ((a) < (b) ? (a) : (b));
y = min(1,2); -> ((1) < (2) ? (1) : (2));
z = min(a + 28, *p) -> z = ((a+28) < (*p) ? (a+28) : (*p));
Macro Definition (4) - Stringization and concat
- Stringization
- Parameter leading with #
#define str(s) #s
#define foo 4
str(foo) // "foo"
- Concatenation
#define COMMAND(name) { #name, name##_command }
COMMAND(quit) // { "quit", quit_command }
Macro Definition (5) - Variadic
- #define eprintf(...) fprintf (stedrr, VA_ARGS)
eprintf ("%s:%d: ", input_file, lineno)
-> fprintf (stderr, "%s:%d: ", input_file, lineno)
#define eprintf(format, ...) fprintf (stderr, format __VA_OPT__(,) __VA_ARGS__)
Lecture 09 [2022.01.18]
Linux Command
-
cc -g
- gdb에게 제공하는 정보를 바이너리에 삽입
- -g 옵션을 사용하지 않고 gdb로 디버깅하면 역어셈블리 코드에서 어셈블리 코드로만 디버깅 가능
-
cc -pg
- 프로파일을 위한 코드 삽입
- -pg 옵션으로 컴파일 → gmon.out(프로파일 정보) → gprof로 gmon.out 파일 분석
gdb Command
- 실행파일과 소스파일이 같은 디렉토리에 있어야 제대로 동작
-
gdb (실행파일)
- 시작 명령
-
run
- 프로그램 실행
-
break (line or *address)
- 정지 명령
- break n : n번째 라인에서 정지 (정지점 생성)
- break Add : Add가 포함된 라인에서 정지 (정지점 생성)
-
clear
- 정지점 삭제
- clear n : n번째 라인 정지점 삭제
-
delete breakpoints
- 정지점 모두 지움
-
step
- 현재 라인 수행 후 정지
- 함수 호출 시 함수 안으로 들어감
- step n : step 명령 n번 수행
-
next
- 현재 라인 수행 후 정지
- 함수 호출 시 함수 다음 라인으로 넘어감
- next n : next 명령 n번 실행
-
print
- 주소나 변수 등을 출력
-
list
- 소스 파일 내용 출력
- list a, b : a ~ b번째 라인의 소스 출력
-
continue
- 다음 정지점까지 코드 실행
-
watch
- 해당 변수에 watchpoint를 설정하여 변수가 바뀔 때마다 현재 값을 출력함
-
info reg
- 특정 레지스터의 정보 출력
-
set
- 특정 메모리 혹은 레지스터에 값을 지정
-
finish
- 현재 함수를 수행하고 빠져나감
-
Quit (q)
- 종료 명령
CPU
- ALU (Arithmetic / Logic Unit)
- CU (Control Unit)
고정소수점 관련 코드
-
부동소수점 대신 고정소수점을 사용하는 이유
- 부동소수점은 컴퓨터에 따라 연산에 많은 에너지를 필요로 함
-
S32_31 => signed long long
-
S16_15 => signed int
-
S8_7 => signed short
-
S4_3 => signed character
#include <stdio.h>
// #### #### #### #### . #### #### #### ####
// S 15 . 16
#define FX_Q_NUM 16
#define FX_2_MINUS_16 1.52587890625e-05F
#define FX_2_PLUS_16 (1<<16)
#define FX_S_15_16 11516
#define FX_SYSTEM FX_S_15_16
typedef int fixed32;
fixed32 fromFloat(float fa)
{
return (fixed32) (fa * FX_2_PLUS_16);
}
float toFloat(fixed32 xa)
{
return ((float) (xa)) * FX_2_MINUS_16;
}
fixed32 fxAdd(fixed32 a, fixed32 b)
{
return fromFloat(toFloat(a)+toFloat(b));
}
fixed32 fxAdd2(fixed32 a, fixed32 b)
{
return a+b;
}
int main()
{
int i = 0;
int ia, ib, ic, ic2;
float fa;
fscanf(stdin, "%d %d", &ia, &ib);
for (i = 0; i < 64*256*256*256; i+=(256*256)){
ic = fxAdd(i, i);
ic2 = fxAdd2(i, i);
fprintf(stdout, "%f + %f : %f, %f diff = %d \n", toFloat(i), toFloat(i), toFloat(ic), toFloat(ic2), ic-ic2);
}
fprintf(stdout, "%d + %d : %d \n", ia, ib, ic);
}
Lecture 10 [2022.01.19]
Linux Command
- ulimit
- 프로세스의 자원 한도를 설정하는 명령
- Soft : 새로운 프로그램을 생성하면 기본으로 적용되는 한도
- hard : 소프트한도에서 최대로 늘릴 수 있는 한도
- 옵션
- -a : 모든 제한 사항을 보여줌
- -c : 최대 코어 파일 사이즈 설정
- -d : 프로세스 데이터 세그먼트의 최대 크기
- -f : shell에 의해 만들어질 수 있는 파일의 최대 크기
- -s : 최대 스택 크기
- -p : 파이프 크기
- -n : 오픈 파일의 최대수
- -u : 오픈파일의 최대수
- -v : 최대 가상메모리의 양
- -S : soft 한도
- -H : hard 한도
숫자의 표현
숫자의 표현 - 2's complement
숫자의 표현 float (IEEE 754)
-
float
-
Others
- half - sign 1, exp 5, fraction 11
- double - sign 1, exp 11, fraction 53
- quadruple - sign 1, exp 15, fraction 113
숫자의 표현 - fixed FX_S03_04 (Q = 4)
- floating point에 비해서 정밀도가 떨어짐
사칙연산
-
덧셈 / 뺄셈
- v = v_a + v_b = iv_a2^(-q) + iv_b2^(-q) = (iv_a + iv_b)*2^(-q)
- iv = iv_a + iv_b
-
곱셈
- v = v_a * v_b = iv_a2^(-q) * iv_b2^(-q) = (iv_a * iv_b)*2^(-2q)
- iv = iv_a * iv_b * 2^(-q) = v * 2^(q)
-
나눗셈
- v = v_a / v_b = iv_a2^(-q) / iv_b2^(-q) = (iv_a / iv_b)
- iv = iv_a / iv_b * 2^(-q)
- iv = iv_a * 2^(-q) / iv_b
Project S17.14
-
s : 부호 비트 -> signed
-
17 : 소수점 위 비트 수
-
14 : 소수점 아래 비트수
-
실제 구현은 int 혹은 long long을 사용하여 구현
-
실제 값은 val / 2^14
-
예 :
typedef int fx_s17_14;
typedef fx_s17_14 fixed;
#define FX_S17_14 ((1<<16)|(17<<8)|(14)) //69902
How to compile for 32bits in 64bits
- 64 bits compile
gcc -pg test.c -m64
- 32 bits compile
gcc -pg test.c -m32
What makes different performance
-
Golden Rule
- Speed - CPU > Memory > Storage > IO > Human
- Register > Cache(1st, 2nd) > Memory > ...
- Locality
- Pipeline
- 구성요소
- 빌드(Build) - 애플리케이션을 컴파일하는 단계
- 테스트(Test) - 코드를 테스트하는 단계
- 릴리스(Release) - 애플리케이션을 리포지토리에 제공하는 단계
- 배포(Deploy) - 코드를 프로덕션에 배포하는 단계
- 검증 및 컴플라이언스(Validation & compliance)
- 빌드 검증 단계는 해당 조직의 필요에 따라 결정
- Clair와 같은 이미지 보안 스캔 툴을 사용하여 알려진 취약점(CVE)과 비교하는 방법으로 이미지의 품질을 보장
- pipelining
- 한 functional unit을 사용하는 동안 다른 unit은 일하지 않음
- unit이 명령어를 처리하는 동안 다음 명령어를 받아와서 처리하는 방식
- 명령어 하나를 처리하는데 걸리는 시간은 그대로지만 throughput(유닛이 일정한 시간에 처리하는 일의 양)을 늘려 더 빨라보이게 만듦 + 실제로 빨라짐
- Error
-
FLOP(Floating Point Operation)
- 컴퓨터의 성능을 수치로 나타낼 때 주로 사용되는 단위
- 초당 부동소수점 연산이라는 의미로 컴퓨터가 1초동안 수행할 수 있는 부동소수점 연산의 횟수가 기준
- 연산식은 FLOPS = cores x clock x (FLOPS/cycle)
ARM 9 - CPI
ARM Compile (optimization)
- 숫자가 높아질수록 세부적인 최적화
- 최적화 후 코드가 변경되기 때문에 디버깅 불가
gprof - GNU Profiling
- gprof - display call graph profile data
- Compile with -pg option
cc -pg -Wall test.c
- Execute program and generate gmon.out file
a.out
- Execute gprof
gprof a.out gmon.out
-
- 첫번째 열을 보면 총 걸린 시간의 % 확인 가능
- self를 통해 함수 안에서 발생한 연산 시간 확인 가능
- gprof할 때 충분한 call이 필요하고 함수 호출은 굉장히 비쌈
- 10~20%의 오차가 항상 발생
Lecture 11 [2022.01.20]
rgba.c 코드
#include <stdio.h>
typedef unsigned int t_rgba;
// input value must be 0~255
/*
방법 1. 함수 만들기
unsigned int fromRGBA(int r, int g, int b, int a)
{
if (r > 255 || r < 0)
r = 0;
if (g > 255 || g < 0)
g = 0;
if (b > 255 || b < 0)
b = 0;
if (a > 255 || a < 0)
a = 0;
if문 성능 나빠짐
// return r*256*256*256 + g*256*256 + b*256 + a*1;
// return ((r<<24)+(g<<16)+(b<<8)+a);
// return ((r<<(24+g))<<(16+b))<<(8+1);
// return (r<<24|g<<16|b<<8|a);
return ((r&0xff)<<24)|((g&0xff)<<16)|((b&0xff)<<8)|(a&0xff);
}
*/
// 방법 2. macro
#define fromRGBA(r,g,b,a) ((((r)&0xff)<<24)|(((g)&0xff)<<16)|(((b)&0xff)<<8)|((a)&0xff))
#define F_NUM_1_255 (1.0f/255.0f)
t_rgba mul_float(t_rgba c1, t_rgba c2){
float r1, g1, b1, a1;
float r2, g2, b2, a2;
int ir, ig, ib, ia;
r1 = (float) ((c1 >> 24) & 0xff) * F_NUM_1_255;
g1 = (float) ((c1 >> 16) & 0xff) * F_NUM_1_255;
b1 = (float) ((c1 >> 8) & 0xff) * F_NUM_1_255;
a1 = (float) ((c1 >> 0) & 0xff) * F_NUM_1_255;
r2 = (float) ((c2 >> 24) & 0xff) * F_NUM_1_255;
g2 = (float) ((c2 >> 16) & 0xff) * F_NUM_1_255;
b2 = (float) ((c2 >> 8) & 0xff) * F_NUM_1_255;
a2 = (float) ((c2 >> 0) & 0xff) * F_NUM_1_255;
ir = (int) ((r1 * r2) * 255.0f);
ig = (int) ((g1 * g2) * 255.0f);
ib = (int) ((b1 * b2) * 255.0f);
ia = (int) ((a1 * a2) * 255.0f);
return fromRGBA(ir, ig, ib, ia);
}
t_rgba mul_int(t_rgba c1, t_rgba c2)
{
unsigned int r1, g1, b1, a1;
unsigned int r2, g2, b2, a2;
unsigned int r, g, b, a;
r1 = c1 >> 24 ; r2 = c2 >> 24 ;
g1 = (c1 >> 16) & 0xff ; g2 = (c2 >> 16) & 0xff;
b1 = (c1 >> 16) & 0xff ; b2 = (c2 >> 8) & 0xff;
a1 = c1 & 0xff ; a2 = c2 & 0xff;
r= (r1 * r2) / 255;
g= (g1 * g2) / 255;
b= (b1 * b2) / 255;
a= (a1 * a2) / 255;
return fromRGBA(r,g,b,a);
}
int main()
{
int red, green, blue, alpha;
t_rgba rgba_1, rgba_2, rgba_3;
// input value must be 0~255 : 0.0~1.0
// rgba_1 [rrrrrrrr][gggggggg][bbbbbbbb][aaaaaaaa]
printf("input 4 values with 0~255 : ");
scanf("%d %d %d %d", &red, &green, &blue, &alpha);
rgba_1 = fromRGBA(red, green, blue, alpha);
printf("%d %d %d %d : %u 0x%08x\n", red, green, blue, alpha, rgba_1, rgba_1);
rgba_2 = mul_float(rgba_1, rgba_1);
printf("%d %d %d %d : %u 0x%08x\n", red, green, blue, alpha, rgba_2, rgba_2);
rgba_3 = mul_int(rgba_1, rgba_1);
printf("%d %d %d %d : %u 0x%08x\n", red, green, blue, alpha, rgba_3, rgba_3);
}
출력 결과
input 4 values with 0~255 : 127 127 127 127
127 127 127 127 : 2139062143 0x7f7f7f7f
127 127 127 127 : 1061109567 0x3f3f3f3f
127 127 127 127 : 1061109567 0x3f3f3f3f
Lecture 12 [2022.01.24]
Final Project (fx_s17.14)
- fx_head.h
#pragma once
#define FX_S17_14 ((1<<16) | (17<<8) | (14))
// Operation Preference
#define FX_OP_FLOAT 1
#define FX_OP_PRECISION 2
#define FX_OP_FAIR 3
#define FX_OP_PERFORMANCE 4
- fx_s17_14.h
#include "fx_head.h"
#include <math.h>
#define FX_POINT FX_S17_14
#define FX_Q_NUM (FX_POINT & 0xFF) // 14
// If you want calculate with high precision set 64
#define FX_SYSTEM_INTEGER 64 // 32 or 64
#define FX_SYSTEM_FLOAT 64 // 32 or 64
#define FX_DATA_TYPE signed int
typedef int fx_s17_14;
typedef fx_s17_14 fixed;
#define fromDouble(d) ((fixed)((d)*DOUBLE_Q_VALUE))
#define toDouble(d) ((double)(d)*DOUBLE_1_Q_VALUE)
#define fromFloat(d) ((fixed)((d)*FLOAT_Q_VALUE))
#define toFloat(d) ((float)(d)*FLOAT_1_Q_VALUE)
// CONSTANTS
#define FLOAT_Q_VALUE (float)(1<<FX_Q_NUM)
#define DOUBLE_Q_VALUE (double)(1<<FX_Q_NUM)
#define FLOAT_1_Q_VALUE (float)(1.0f/FLOAT_Q_VALUE)
#define DOUBLE_1_Q_VALUE (double)(1.0f/DOUBLE_Q_VALUE)
#define FX_PI fromDOUBLE(M_PI)
// One of FX_OP_FLOAT, FX_OP_PRECISION, FX_OP_FAIR, FX_OP_PERFORMANCE
#define FX_OP_PREFERENCE FX_OP_FLOAT
extern fixed fxAdd_float(), fxAdd_precision(), fxAdd_fair(), fxAdd_performance();
extern fixed fxSub_float(), fxSub_precision(), fxSub_fair(), fxSub_performance();
extern fixed fxMul_float(), fxMul_precision(), fxMul_fair(), fxMul_performance();
extern fixed fxDiv_float(), fxDiv_precision(), fxDiv_fair(), fxDiv_performance();
- project_main.c
#include "fx_s17_14.h"
#include <stdio.h>
int main()
{
printf("%f : %d\n",1.0, fromDouble(1.0));
printf("%f : %f\n",1.3*0.3, toFloat(fxMul_float(fromDouble(1.3),fromDouble(0.3)))) ;
}
- cc project_main.c fx_s17_14.c 실행 결과 1.000000 : 16384 0.390000 : 0.389954
Make (GNU make)
- Lots of source files: foo1.h, foo2.h, foobar1.cpp ...
- How to manage them allocated
- Compiling is not easy
- different target system
- different purpose of compiling - debug, release, preprocessor ...
- compile what we need to
- dependency
- Solution is
- make
Understanding MAKE
-
파일 간의 종속관계를 파악하여 Makefile에 적힌 대로 컴파일러에 명령하고 SHELL 명령이 순차적으로 실행될 수 있게 함
-
MAKE를 쓰는 이유
- 각 파일에 대한 반복적 명령의 자동화로 인한 시간 절약
- 프로그램의 종속 구조를 빠르게 파악할 수 있으며 관리가 용이
- 단순 반복 작업 및 재작성을 최소화
-
Makefile의 구성
- 목적파일(Target) : 명령어가 수행되어 나온 결과를 저장할 파일
- 의존성(Dependency) : 목적파일을 만들기 위해 필요한 재료
- 명령어(Command) : 실행되어야 할 명령어들
- 매크로(Macro) : 코드를 단순화 시키기 위한 방법
-
Makefile 작성규칙
목표파일 : 목표파일을 만드는데 필요한 구성요소들
목표를 달성하기 위한 명령 1
목표를 달성하기 위한 명령 2
- 더미타겟
- 파일을 생성하지 않는 개념적인 타겟
clean :
rm *.o projectfile
의 형태
실행할 때는 make clean
으로 명령하여 현재 디렉토리의 모든 object 파일과 생성된 실행파일인 projectfile을 제거할 수 있음
-
매크로 사용 작성 규칙
- 매크로를 참조할 때는 소괄호나 중괄호로 둘러싸고 앞에 $
- 탭으로 시작할 수 없으며 :, =, #, "" 등의 기호는 이름에 사용할 수 없음
- 매크로는 반드시 치환될 위치보다 먼저 정의
-
내부 매크로 사용
-
Make에서 컴파일 할 파일이 변경되는 경우 이미 실행 파일이 만들어져 있더라도 다시 만듦
-
touch 명령을 통해 timestamps가 바뀌더라도 다시 make 명령 실행 가능
CMake
- 요구 CMake 최소 버전
CMAKE_MINIMUM_REQUIRED (VERSION 2.8)
- 프로젝트 이름 및 버전
PROJECT ("andromeda")
SET (PROJECT_VERSION_MAJOR 0)
SET (PROJECT_VERSION_MINOR 1)
- 빌드 형상(Configuration) 및 Makefile 생성 여부
SET (CMAKE_BUILD_TYPE Debug)
SET (CMAKE_VERBOSE_MAKEFILE true)
Lecture 13 [2022.01.25]
Linux Command
-
ps
- 현재 실행중인 프로세스 목록과 상태를 보여줌
-
ps -l
- 더 구체적으로 보여줌
vi Command
-
:r
- 파일을 읽음
-
:!
- 명령어를 실행
CPU Code
Context Switching
- 현재 진행하고 있는 task(process, thread)의 상태를 저장하고 다음 진행할 task의 상태 값을 읽어 적용하는 과정
- 진행과정
- Task의 대부분 정보는 Register에 저장되고 PCB(Process Control Block)로 관리됨
- 현재 실행하고 있는 Task의 PCB정보를 저장
- 다음 실행할 Task의 PCB 정보를 읽어 Register에 적재하고 CPU가 이전에 진행했던 과정을 연속적으로 수행
- Context Switching이 발생하면 많은 비용이 소요됨
Process 상태
- RUN
- fg
- bg
- STOP
- KILL
Fork function
- 프로세스가 자기 자신을 복제하는 동작
- 시스템 호출의 일종으로 커널 안에서 구현
- 복제 대상을 부모 프로세스, 결과물을 자식 프로세스라고 함
- unistd.h를 include하여 사용함
- 프로세스가 가지는 고유한 번호를 프로세스 ID라고 함
- fork함수 성공시 부모 프로세스는 자식 프로세스의 프로세스 ID를 리턴
Thread
- 프로세스 내에서 실제로 작업을 수행하는 주체
- 모든 프로세스에는 한 개 이상의 스레드가 존재하여 작업을 수행함
- 두개 이상의 스레드를 가지는 프로세스를 멀티스레드 프로세스라고 함
- 장점
- 프로세스에 비해 생성 및 종료시간, 스레드간 전환시간이 짧음
- 프로세스의 메모리, 자원등을 공유하므로 커널의 도움없이 상호간 통신이 가능
Process vs Thread
- Process
- 운영체제로부터 자원을 할당받는 작업의 단위
- 실행 중인 프로그램
- 디스크로부터 메모리에 적재되어 CPU의 할당을 받을 수 있는 것
- 많은 자원과 시간을 소비
- Thread
- 프로세스가 할당받은 자원을 이용하는 실행의 단위
- 프로세스의 실행 단위
- 한 프로세스 내에서 동작되는 여러 실행 흐름으로 프로세스 내의 주소 공간이나 자원을 공유
- 각각의 쓰레드는 독립적인 작업을 수행하기 때문에 각자의 스택과 PC 레지스터 값을 가짐
system - system call
#include <stdlib.h>
int system(const char *command);
execl("/bin/sh", "sh", "-c", command, (char *) 0);
int execl(const char *path, const char *arg, ...
/* (char *) NULL */);
popen
#include <stdio.h>
FILE *popen(const char *command, const char *type);
실행시킨 명령어와 표준 입력/ 표준 출력을 주고 받기 위한 용도로 사용함. (Input/Output pipe를 open하기 위한 용도로 사용함)
Core vs Thread
thread.h (C11)
#include <streads.h>
#include <stdio.h>
int run(void *arg)
{
printf("Hello world of C11 threads.");
return 0;
}
int main(int argc, const char *argv[])
{
thrd_t thread;
int result;
thrd_create(&thread, run, NULL);
thrd_join(&thread, &result);
printf("Thread return %d at the end \n", result);
}
pthread.h (POSIX)
#include <pthread.h>
#include <stdio.h>
void *run (void *arg)
{
printf("Hello world of POSIX threads.");
return 0;
}
int main()
{
pthread_t thread;
int result;
pthread_create(&thread, NULL, run, NULL );
pthread_join(thread, &result);
printf("Thread return %d at the end\n", result);
}
- POSIX Thread의 약자로 유닉스 계열 POSIX 시스템에서 병렬적으로 작동하는 소프트웨어를 작성하기 위하여 제공하는 API
- 즉, 스레드를 편하게 만들 수 있게 도와주는 API
- API (Application Programming Interface)
- 애플리케이션 소프트웨어를 빌드하고 통합하기 위한 정의 및 프로토콜 세트
- 구현 방식을 알지 못하는 제품 또는 서비스와도 통신할 수 있음
- 애플리케이션 개발을 간소화하여 시간과 비용을 절약할 수 있음
- 새로운 툴과 제품을 설계하거나 기존 툴과 제품을 관리할 때 유연성을 높이고 설계, 관리, 사용 방법을 간소화 가능
- 리소스에 대한 액세스 범위를 넓히는 동시에 보안과 제어 유지
- API (Application Programming Interface)
Lecture 14 [2022.01.26]
vi editor
- ~/.vimrc
- vi editor모드로 전환할 때 실행될 명령어들을 저장하는 파일
- set num
- vi editor를 실행하면 자동으로 라인 수가 표시됨
- set tabstop=(숫자)
- tab을 누르면 이동하는 칸 수를 지정
POSIX
- 다른 운영체제들 사이의 호환성을 위해 IEEE에서 만든 표준
- 한 운영체제에서 개발한 프로그램을 다른 운영체제에서도 쉽게 돌아가도록 하는 것
- UNIX 기반
UNIX
-
주로 서버용 컴퓨터에서 사용되는 운영체제
-
특징
- 시분할 시스템을 위해 설계된 대화식 운영체제
- 소스가 공개된 개방형 시스템
- 대부분 C언어로 작성되어 있어 이식성이 높음
- 장치, 프로세스 간 호환성이 놓음
- 크기가 작고 이해하기가 쉬움
- 다중 사용자, 다중 작업을 지원
- 많은 네트워킹 기능을 제공하여 통신망 관리용 운영체제로 적합
- 트리구조의 파일 시스템을 가지고 있음
- 전문적인 프로그램 개발에 용이
- 다양한 유틸리티 프로그램들이 존재
-
구성
- 커널(Kernel)
- 유닉스의 가장 핵심적인 부분
- 컴퓨터가 부팅될 때 주기억장치에 적재된 후 상주되면서 실행
- 하드웨어를 보호하고 프로그램과 하드웨어 간의 인터페이스 역할을 담당
- 프로세스 관리, 기억 장치 관리, 파일 관리, 입출력 관리, 프로세스 간 통신, 데이터 전송 및 변환 기능 수행
- 쉘(Shell)
- 사용자의 명령어를 인식하여 프로그램을 호출하고 명령을 수행하는 명령어해석기
- 시스템과 사용자 간 인터페이스를 담당
- 명령어가 포함된 파일 형태로 존재하며 보조기억장치에서 교체 가능
- 파이프 라인 기능을 지원하고 입출력 재지정을 통해 입력, 출력 방향 변경
- 유틸리티 프로그램(Utility Program)
- 일반 사용자가 작성한 응용프로그램을 처리하는데 사용
- Dos에서의 외부 명령어에 해당
- 에디터, 컴파일러, 인터프리터, 디버거 등이 포함됨
- 커널(Kernel)
buffer
- 입출력을 수행하는데에 있어 속도 차이를 극복하기 위해 사용하는 임시 저장 공간
- 프로그래밍이나 운영체제에서 사용하는 버퍼는 CPU와 보조기억장치 사이에서 사용되는 임시 저장 공간을 의미
- CPU 내부의 캐시메모리 보다는 느리지만 보조기억장치보다 빠른 주기억 장치를 이용
- 과정
- 보조기억장치가 주기억장치의 버퍼로 데이터를 보냄
- CPU가 다른 일들을 처리한 후 시간이 남으면 버퍼를 확인하여 쌓여있는 데이터를 한번에 처리함
Lecture 15 [2022.01.27]
Software Testing
-
실제 결과가 예상 결과와 일치하는지 확인하고 소프트웨어 시스템에 결함이 없는지 확인하는 활동
-
하나 이상의 관심 속성을 평가하기 위한 소프트웨어 구성 요소 또는 시스템 구성 요소의 실행을 포함
-
실제 요구 사항과 달리 오류, 결함 또는 누락된 요구 사항을 식별하는데 도움이 됨
-
수동으로 또는 자동화 된 도구를 사용하여 수행 가능
-
중요성
- 소프트웨어 버그가 비싸거나 위험할 수 있기 때문
- 소프트웨어 버그는 잠재적으로 금전적 손실과 인적 손실을 초래할 수 있음
-
테스트 방식
-
SW 내부 구조 파악 여부
- 화이트박스 테스트 (White Box Test)
- 응용 프로그램의 내부 구조, 동작을 디테일하게 거사하는 테스트 방식
- 유형
- 경로 테스트
- 루프 테스트
- 상태 테스트
- 블랙박스 테스트 (Black Box Test)
- 소프트웨어의 내부 구조나 작동 원리를 모르는 상태에서 동작을 검사하는 방식
- 유형
- 기능 테스트
- 비 기능 테스트
- 회귀 테스트
- 화이트박스 테스트 (White Box Test)
-
소프트웨어 실행 여부
- Static
- 프로그램을 실행하지 않고 소스 코드 전체 또는 일부를 분석하는 기법
- Dynamic
- SW를 실행하여 다양한 입력 값에 대해 기대하는 결과 값이 나타나는지 확인하는 테스팅 기법
- Static
-
V-model
- v-bind와 v-on의 기능을 합쳐놓은 문법
- 소프트웨어 개발 프로세스로 폭포수 모델의 확장된 형태 중 하나
- 요구 사항 분석에서의 오류, 설계 등 개발 단계의 작업들에 대한 테스트를 포함
소프트웨어 기능안전
- 시스템이나 장비의 총체적 안전의 일환으로 하드웨어 고장, 소프트웨어 오류, 운영자 오류, 환경적 영향등에 대한 안전 관리
- IEC61508 안전표준을 기반
정적 테스트
- 소프트웨어를 실행시키지 않고 결함을 검출하는 방법
- 특징 : 코딩 규칙, 가이드 준수 여부 검사
- 장점 : 코드 실행 전 사용
- 단점 : 정확도 상대적 낮음
- 인스펙션
- 공식적 검사
- 프로그램을 실행하지 않고 산출물을 대상으로 공식적 검토, 결함 발견 과정
- 구성 : 이해 관계자, 중재자, 검토자, 기록자
- 피어 리뷰
- 동료 검토
- 프로젝트 수행과정에서 각 단계 별 산출물, 제품에 대해 동료들이 상호 교차하여 검토 수행하는 활동
- 구성 : 프로젝트 팀원, 체크리스트
- 워크쓰루
- 비공식 검토
- 프로젝트 개발 초기에 팀 내에서 수행하는 검토 과정
- 구성 : 프로젝트 팀원
구분 | 인스펙션 | 피어 리뷰 | 워크쓰루 |
---|---|---|---|
공식성 | Formal | Mid Formal | Informal |
개념 | 산출물 대상 공식 검토 | 개발단계별 산출물 대상 동료 검토 | 소팀 내 결함 해결방안 상호 검토 |
목적 | 요구사항 확인 | 계획의 적합성 평가 | 결함 발견 |
기법 | 이해관계자 산출물 검사 | 검토 회의 | 집중 검토 기법 |
규모 | 3 ~ 6명 | 3명 이상 | 2 ~ 7명 |
참석자 | 이해관계자 | 경영자, 개발 관리자 | 개발자 |
리더십 | 훈련된 중재자 | 선임 관리자 | 개발자 본인 |
결함 기록 | 공식 기록 | 공식 기록 | 개인별 기록 |
동적 테스트
- 소프트웨어 실행을 통해 소프트웨어에 존재하는 결함을 검출하는 방법
- 특징 : 단독분석보다 정적 기법 병행 수행 적용
- 장점 : 오류 탐색 정확도 높음
- 단점 : 코드 전체 수행 어려움