{"id":23951311,"url":"https://github.com/kwaksj329/practicalcoding","last_synced_at":"2026-04-17T06:03:18.113Z","repository":{"id":114569859,"uuid":"468079689","full_name":"kwaksj329/PracticalCoding","owner":"kwaksj329","description":"Linux command, advanced C language \u0026 various programming tools","archived":false,"fork":false,"pushed_at":"2022-03-09T20:33:04.000Z","size":5447,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-24T09:21:41.975Z","etag":null,"topics":["bash","gnu-debugger","linux"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kwaksj329.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-03-09T20:18:20.000Z","updated_at":"2022-03-13T17:28:14.000Z","dependencies_parsed_at":null,"dependency_job_id":"6396b22c-e90a-4e8d-bf14-f2741c9b7840","html_url":"https://github.com/kwaksj329/PracticalCoding","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/kwaksj329/PracticalCoding","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kwaksj329%2FPracticalCoding","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kwaksj329%2FPracticalCoding/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kwaksj329%2FPracticalCoding/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kwaksj329%2FPracticalCoding/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kwaksj329","download_url":"https://codeload.github.com/kwaksj329/PracticalCoding/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kwaksj329%2FPracticalCoding/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31917372,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-16T18:22:33.417Z","status":"online","status_checked_at":"2026-04-17T02:00:06.879Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bash","gnu-debugger","linux"],"created_at":"2025-01-06T12:59:28.802Z","updated_at":"2026-04-17T06:03:18.097Z","avatar_url":"https://github.com/kwaksj329.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Practical Coding Report\n\n### `sshid` : pcc001\n### `name` : 곽수정 ✨\n### `id` : 201921085\n\n***\n\n## Contents  \n\n1. [ Lecture 1 ](#lecture-1)\n2. [ Lecture 2 ](#lecture-2)\n3. [ Lecture 3 ](#lecture-3)\n4. [ Lecture 4 ](#lecture-4)\n5. [ Lecture 5 ](#lecture-5)\n6. [ Lecture 6 ](#lecture-6)\n7. [ Lecture 7 ](#lecture-7)\n8. [ Lecture 8 ](#lecture-8)\n9. [ Lecture 9 ](#lecture-9)\n10. [ Lecture 10 ](#lecture-10)\n11. [ Lecture 11 ](#lecture-11)\n12. [ Lecture 12 ](#lecture-12)\n13. [ Lecture 13 ](#lecture-13)\n14. [ Lecture 14 ](#lecture-14)\n\n***\n\n## Lecture 1  \n\n##### - 2022. 01. 04   \n\n* git을 사용하기 위한 프로그램 설치\n\n* Basic Linux Command\n\n### `ls`\n\n현재 디렉토리에 어떤 파일이 있는지 list를 보여주는 명령어  \n\n```bash\n$ ls -l                   # 파일의 상세 정보 표시\n$ ls -a                   # 숨어있는 파일들도 표시\n$ ls -al pcc001           # pcc001 디렉토리의 모든 파일 표시\n```\n\n### `pwd`  \n\nprint working directory : 현재 디렉토리 보여줌  \n\n### `hostname`  \n내가 지금 어떤 컴퓨터를 쓰는지 알고싶다면 사용  \n\n```bash\n$ hostname  \nKwakui-MacBookPro.local\n```\n\n### `who`  \n컴퓨터에 누가 들어왔는지 보고싶을 때 사용  \n호스트에 로그인한 사용자의 정보를 출력\n\n### `wc`  \nword count  \n주어지는 파일 또는 표준 입력의 바이트, 문자, 단어 그리고 줄(라인) 수를 출력해주는 명령어\n\n### `who | wc`  \nwho의 output이 다음 명령 wc에 들어감 : 현재 접속자 수 보여줌  \n\n### `who | sort`  \nwho의 output 정렬해서 보여줌\n\n### `mkdir`  \n디렉토리 생성하는 명령어  \n\n```bash\n$ mkdir pcc         # pcc 디렉토리 생성, 이미 디렉토리가 존재한다면 에러 발생\n```  \n\n### `cd`  \nchange directory  \n디렉토리를 이동하는 명령어\n\n```bash\n$ cd                # cd 뒤에 디렉토리 입력 안하면 home directory로 이동\n$ cd ~              # home directory로 이동, 위 명령어와 동일\n$ cd ..             # 윗 디렉토리로 이동\n$ cd lec01          # lec01 디렉토리로 이동\n```\n\n### `vi hello.c`  \nvi 에디터로 파일 생성 후 편집  \n\n * 3가지 mode: normal, insert, command mode  \n\n    * normal 모드에서 i 를 눌러 insert mode로 전환 후 타이핑  \n\n        * 한 글자 지우기: delete 키 / x 키, undo: u 키, 커서 뒤에 append: a 키  \n\n    * insert mode에서 esc 눌러 빠져나오면 normal mode로 전환됨  \n\n    * normal mode에서 command mode로 들어가려면 : 누름  \n\n        * ex) **:wq** = write \u0026 quit  \n\n\n\n### `cc hello.c`  \nhello.c 파일 컴파일 -\u003e 기본적으로 a.out 실행파일 생성됨  \n\n### `mv`  \n파일을 이동시키는 명령어  \n\n```bash\n$ mv a.out hello.c pcc            # a.out와 hello.c 파일을 pcc 디렉토리로 이동시킴  \n$ mv hello.c hola.c               # hello.c 파일의 이름을 hola.c 로 변경 가능\n```\n\n_cp는 원본 파일이 남아있지만 mv는 원본 파일이 남아있지 않아 파일 이름 변경시에도 사용 가능하다._  \n\n### `passwd`  \n비밀번호 변경 가능, 현재 비밀번호 입력한 뒤 새로운 비밀번호로 변경  \n\n### `chmod`  \n파일의 모드를 변경하는 명령어\n  \n| 파일 소유자 | 그룹 | 그 외 사용자 |\n|:--------:|:----:|:--------:|\n|read, write, execute| read, write, execute | read, write, execute|\n|4 2 1| 4 2 1 | 4 2 1 |\n\n|  변경 전  |  명령어  |  변경 후  |\n|:-------:|:-------:|:-------:|\n|drwxrwxrwx| chmod 700 pcc001 | drwx------|\n| drwx------| chmod 777 forAll | drwxrwxrwx|  \n\n* 예시) `drwxrw----- pcc039 pcc forAll`  \n    * forAll이라는 디렉토리의 소유자는 pcc039이며 그룹은 pcc 이다.\n    * 디렉토리의 소유자인 pcc039는 read, write, execute 권한을 가진다.\n    * 그룹 pcc에 속한 사용자는 read와 write 권한을 갖는다.\n    * 그 외 사용자는 아무 권한도 갖지 않는다.\n    * _super user는 항상 모든 권한을 갖고 있다._\n\n* 예시) `d---rwx--- pcc039 pcc forAll`\n    * 디렉토리의 소유자인 pcc039는 아무 권한도 갖지 않는다.\n    * 따라서 소유자 pcc039는 forAll 디렉토리에 들어가지 못한다!\n    * **디렉토리에 들어가려면 실행 권한(x = execute)이 필요하다.**\n    * 디렉토리 소유자와 others는 아무 권한이 없고, pcc group에 속한 사용하즌 read, write, execute 권한을 갖는다.\n\n* 예시) `d---rwxrwx pcc039 pcc forAll`\n    * forAll 디렉토리에 들어갈 수 있는 사람은 소유자 pcc039 빼고 모두이다.  \n    즉, group에 속한 사용자, 그 외 사용자, 그리고 super user이다.\n    * super user = root = 이 기계를 관리하는 사람\n\n### `groups`  \n내가 속한 그룹 보여줌\n\n### `whoami`  \n현재 로그인한 사용자의 id 출력\n\n```bash\n$ whoami\npcc001\n```\n\n### `cat`  \n어떤 파일의 내용을 보는 명령어\n\n```c\n$ cat hello.c\n#include \u003cstdio.h\u003e\n\nint main()\n{\n\tprintf(\"Hello World \\n\"); //Comment\n}\n```\n\n### `whoami \u003e\u003e output`  \nwhoami의 결과인 pcc001이 output 파일에 추가됨\n\n### `history`  \n내가 입력한 명령어 이력들 보기  \n\n***\n\n## Lecture 2\n  \n##### - 2022. 01. 05 \n  \n\n### `Computer Hardware System`  \n\n\u003cdiv style=\"text-align : center;\"\u003e\n    \u003cimg src=./img/hardware_sys.png width=\"70%\"/\u003e  \n\u003c/div\u003e\n\n_lec01 실습: output device에 Hello World를 출력하도록 명령함  \n실행 파일명: a.out_  \n\n* CPU: central processing unit  \n* Memory: RAM, ROM  \n* Input Devices: 키보드, 마우스, 마이크  \n* Output Devices: 모니터, 프린터, 스피커  \n* Storage Devices: hhd, ssd, 파일이 들어있는 곳\n\n**Q**) Storage에 들어있는 a.out 파일을 CPU가 바로 실행할 수 있다? [ **X** ]\n\u003e CPU는 storage device에 들어있는 파일을 직접 실행할 수 있는 경우가 없다!\n\n**Q**) CPU는 output device에 데이터를 내보낼 수 있다? [ **X** ]\n\u003e 직접 output device에 데이터를 내보낼 수 없다! 따라서 메모리에 두어야함.  \n\n* Storage에 저장되어 있는 a.out 프로그램을 실행하려면 메모리에 두어야하고, 그럼 CPU가 메모리에서 하나씩 가져다가 실행함  \n\n* 메모리 중에서 초록색으로 표시된 부분은? **buffer**\n\u003e input device가 쓰는 버퍼: input buffer  \n\u003e output device가 쓰는 버퍼: output buffer  \n\n### `Computer system 구성요소`  \n \n\u003cdiv style=\"text-align : center;\"\u003e\n    \u003cimg src=./img/computer_sys.png width=\"70%\"/\u003e  \n\u003c/div\u003e\n\n* User, data, hardware, software 로 구성되어 있다.\n\n### `Software`  \n* Application software  \n* System software: os, compiler, device driver  \n    * system software, os: 사용자가 하드웨어를 쓰기 쉽게 해주는 기능 제공\n    * os ( 운영체제 ): 하드웨어 바로 위에 존재  \n\n\u003cdiv style=\"text-align : center;\"\u003e\n    \u003cimg src=./img/software.png width=\"70%\"/\u003e  \n\u003c/div\u003e\n\n* bash: git-scm 설치 후 프롬프트 나오고 대화형으로 이 유틸리티를 사용할 수 있도록 만들어주는 것\n\n* HW에 Hello world! 가 출력 되려면?  \n    * hello.c를 컴파일해서 a.out 이라는 app 을 만든다. -\u003e bash에서 a.out을 실행시킨다.  \n    * HW에 출력하기 위해 shell에서 실행되어 system call 중 printf를 사용하여 커널에게 요청하고, 커널이 hw에게 출력하기를 요청하여 모니터에 Hello World! 가 출력된다.  \n\n### `Linux kernel`\n\n\u003cdiv style=\"text-align : center;\"\u003e\n    \u003cimg src=./img/linux_kernel.png width=\"75%\"/\u003e  \n\u003c/div\u003e\n\n* Linux Kernel에서도 위 **Computer hardware system** 그림에서 볼 수 있는 5가지 구성 요소를 모두 가지고 있다.  \n즉 OS는 Input \u0026 Output device, Memory, CPU, Storage devices와 같은 hw를 사용자가 사용하기 쉽게 만들어준다.\n\n* Linux kernel \u0026 Computer hardware system\n    * I/O subsystem - _Input \u0026 Output device_\n    * Memory management subsystem - _Memory_\n    * Process management subsystem - _CPU_\n    * File systems - _Storage devices_  \n\n* 위로 갈 수록 sw, 아래로 갈 수록 hw와 가깝다. 예를 들어 Network 장치를 이용한 통신을 위한 sw는 socket이다.  \n\n* Processor != Process != Thread  \n\n\u003cdiv style=\"text-align : center;\"\u003e\n    \u003cimg src=./img/terminal.png /\u003e  \n\u003c/div\u003e\n\n* Terminal을 이해하기 위해서는 옛날 컴퓨터 사용방법 생각해보기  \n    * 하나의 컴퓨터에 통신선을 통해 터미널과 연결하여 사용했었음  \n    * 옛날에 사용하던 터미널에도 CPU, memory, I/O device 등 존재했지만 실제로 계산하는 중심적인 서비스를 제공하는 것은 async mainframe host였기 때문에 상대적으로 터미널(단말)이라고 불렀다.  \n\n* 사용자가 hw를 사용하기 편리하도록 기본적으로 설치되는 시스템 소프트웨어: 운영체제  \n\n* 터미널 앞에는 컴퓨터의 4대 구성요소 중 하나인 user가 있고, HW 관점으로 봤을 때 사용자와 직접적으로 맞닥뜨리는 종점( 단말 )이 **Terminal**이다.  \n\n* Terminal = character device = Input 장치이면서 output 장치이다.  \n\n### `Lec02 실습`\n\n* 리눅스에서는 모든 컴퓨터 자원, resource를 파일로 관리한다.  \n\n* git bash를 여는 순간 터미널이 열린다. 터미널의 타입을 xterm-256color로 설정하면 색이 설정되어 나온다.\n\n* $ = prompt = 예전에는 컴퓨터 사용하는 시간만큼 돈을 냈었다.  \n\n* 명령어를 기다리고 있다가 명령어를 수행하는 프로그램 이름은? **shell**\n\n### `ssh`  \n리눅스 서버에 원격 접속할 때 사용하는 명령어\n\n```bash\n$ ssh pcc001@git.ajou.ac.kr\n```\n\n### `ps`  \n내가 실행하는 process 보고 싶을 때 사용하는 명령어  \n\n```bash\n$ ps\n    PID    TTY      TIME        CMD\n    5655   pts/8    00:00:00    bash\n    9159   pts/8    00:00:00    ps\n```\n_bash를 실행하는 중 \u0026 ps 명령어도 실행되고 있었으므로 표시됨_  \n* `PID` = process id = 리눅스 내부에서는 process들이 번호로 관리됨  \n* `TTY` = terminal  \n\n### `tty`  \n리눅스 device 중 콘솔/터미널을 의미함  \n\n```bash\n$ tty\n/dev/pts/8\n```  \n\n* 리눅스 운영체제는 컴퓨터의 모든 자원을 파일로 관리하며, 그 파일은 disk이다.  \nDisk는 디렉토리를 찾아서 갈 수 있다.  \n\n### `cd /dev`  \n\n/dev = device 파일을 위한 디렉토리이다.  \n장치 드라이버, 터미널, 프린터 등 주변 장치들을 나타내는 파일들이 존재한다.  \n\n* d - directory\n* c - character device\n* b - block device\n* l - simbolic link  \n\n_permission 앞에 붙은 문자는 파일의 종류를 나타낸다._\n\n### `cd /dev/pts`  \n\n내 device pts가 존재하는 디렉토리  \n\n```bash\ncrw--w----  1  hwan  tty  136,  8  1월  5  14:19  8\n```  \n\n**Q**) 위 /dev/pts에 존재하는 8번 파일에 대해 설명하세요.  \n\u003e 8이라고 하는 파일은 character device 입니다.  \n8 device를 소유한 hwan은 read, write 할 수 있습니다.  \n8 파일을 소유한 tty 그룹은 write 할 수 있는 권한이 있으며 이 외의 사용자는 아무 권한도 없습니다.  \n\n* 위 8번 device에 대해 권한 변경 가능 -\u003e ex) chmod 777 8\n\u003e echo pcc001 \u003e 8 으로 입력 가능  \n\n### `wall`  \nwrite all = 모두에게 메세지 보낼 수 있음, ctrl + d 로 메세지 입력 종료  \n\n### `write pcc001`  \nwall과 같이 메세지를 보낼 수 있는 명령어, write pcc001은 pcc001에게 메세지를 보내게 된다.  \n\n### `mesg n`  \nmessage no = write permission turned off  \n\n### `biff`  \n이메일이 오면 벨을 울리게 하는 명령어, 개발한 사람의 옆집 개 이름  \n\n\u003e 리눅스 명령어에서 어떤 규칙을 찾는 것은 불가능하다.  \n명령어의 word 선택은 규칙이 없다.\n\n### `man`  \n각종 명령어와 프로그램 사용법, 메뉴얼을 보여준다.\n\n```bash\n$ man cat       # cat 명령어의 메뉴얼을 보여준다.\n```  \n\n```bash\n$ man cp        # cp 명령어의 메뉴얼을 보여준다.\n```  \n\n\u003cdiv style=\"text-align : center;\"\u003e\n    \u003cimg src=./img/man_cp.png width=\"75%\"/\u003e  \n\u003c/div\u003e  \n\n* `cp [OPTION]` -\u003e [OPTION]은 생략할 수 있다.  \n* `cp [OPTION] ...` -\u003e ...은 여러 옵션이 붙을 수 있음을 의미한다.  \n* `cp [OPTION] ... SOURCE ... DIRECTORY` -\u003e SOURCE ...은 SOURCE가 여러개 붙을 수 있다는 뜻이다.  \n\n**tab을 습관적으로 사용하기! -\u003e 파일명 입력할 때 실수를 줄여주는 방법**  \n\n### `반드시 알아야 할 단축키`  \n* ctrl + d: exit, EOF (End Of File)  \n* ctrl + c: kill signal  \n* ctrl + z: suspend signal  \n\n**Q**) ssh로 팔달관에 있는 git.ajou.ac.kr 컴퓨터로 들어갈 수 있다. git.ajou.ac.kr이 우리에게 device를 하나씩 줬는데 무슨 device일까?  \n\u003e Terminal  \n\n**Q**) 나에게 준 터미널이 무엇인지 물어보고 싶다면?  \n\u003e tty 명령어 입력 -\u003e /dev/pts/11  \n/dev/pts/11 터미널을 주고 passward를 물어봐서 일치하면 첫번째로 실행되는 process는 bash임을 알 수 있다.  \n(ps 명령어로 실행중인 process 알 수 있다.)  \n\n### `ls -l 과 ps -l`  \n* ls -l: 파일이 자세히 보임\n* ps -l: process가 상세히 보임\n* 명령어 자체에는 규칙성이 없지만 명령어의 옵션이나 syntex의 규칙은 서로 매우 비슷하다!  \n\n```bash\n$ ps -l\nF S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD\n0 S  4001 18126 18125  2  80   0 -  6054 wait   pts/2    00:00:00 bash\n0 R  4001 18143 18126  0  80   0 -  7551 -      pts/2    00:00:00 ps\n```  \n\n* UID: user id  \n* PID: process id  \n* PPID: parent process id\n* ps process의 부모가 bash임을 알 수 있다.  \n    * ps의 PPID: 18126 == bash의 PID: 18126  \n\n**ls -al 명령어가 hidden 파일 보여주는 것처럼 ps -al 명령어도 hidden process 보여준다.**  \n\n\u003cdiv style=\"text-align : center;\"\u003e\n    \u003cimg src=./img/hello_world.png width=\"75%\"/\u003e  \n\u003c/div\u003e  \n\n**Q**) a.out를 실행하면 왜 모니터에 Hello World! 가 출력될까?  \n\u003e 지금 내가 사용하고 있는 shell 입장에서 shell의 가장 기본이 되는 input 장치와 output 장치 = **표준입출력장치**  \nstdio.h 를 include 했기 때문에 표준입출력장치에 Hello World! 가 출력된다.  \n\n### `stdio.h`  \n\n**Q**) stdio.h 파일은 어디에 있을까?  \n\u003e /usr/bin/include 에 stdio.h가 존재한다!  \n```c\nextern struct _IO_FILE *stdin;\nextern struct _IO_FILE *stdout;\nextern struct _IO_FILE *stderr;\n```\n\n* **리눅스는 모든 device가 파일이다!**  \n\n* I/O stream은 buffer로 이해하면 좋다.  \n\n* vi editor 명령:  \n    * if에 해당하는 endif 찾고 싶다면 **%** 누르기  \n    * 괄호의 짝을 찾을 때도 **%** 누르기\n    * line number 보고 싶다면 **:set number**\n    * 검색하고 싶을 때는 **/검색어** 로 찾기\n\n* /vmlinuz: 커널 파일, boot/vmlinuz-4.15.0-163-generic에 링크되어있다.  \n\n* /var: variable length, log 파일 등 가변 데이터 파일들이 저장된다.  \n\n### `lec02의 hello.c`  \n\n```c\n#include \u003cstdio.h\u003e\n\nint main()\n{\n    FILE *fout;\n    fout = fopen(\"output.txt\", \"w\");\n    fprintf(fout, \"Hello World\\n\");\n}\n```\n\n**Q**) 위 코드를 통해 Hello World가 output.txt 파일에 써질까? [ **X** ]  \n\u003e buffer를 닫지 않았기 때문에 output.txt에 써지지 않는다.  \n\n### `hello.c 수정한 버전`  \n\n```c\n#include \u003cstdio.h\u003e\n\nint main()\n{\n    FILE *fout;\n    fout = fopen(\"output.txt\", \"w\");\n    fprintf(fout, \"Hello World\\n\");\n    fclose(fout);\n}\n```\n\n_이제 Hello World가 output.txt에 저장된다!_  \n\n* CPU가 Hello World라고 쓰면 storage device에 써지지 않음! buffer에 쓰여진다.  \n\n* buffer에 있는 것이 storage device에 저장되는 때는..? 3가지 mode 존재\n    1. memory 크기는 유한대이므로 buffer가 꽉 차면 그 때 storage device에 저장한다.\n    2. 한글자 buffer에 올때마다 storage device에 저장한다. (buffer size: 1byte)\n        * 대신 성능이 나쁘다. -\u003e 일반적으로 memory보다 storage가 속도가 느리기 때문에\n    3. buffer control하는 명령이 왔을 때 storage device에 저장한다.  \n\n### `sleep`  \n뒤 입력 초만큼 sleep 하는 명령어, kill하고 싶다면 **ctrl + c** 누르기  \n\n```bash\n$ sleep 600             # 600초, 10분 동안 sleep\n```  \n\n### `cat`  \n파일(들)을 순서대로 읽고 그 내용을 읽은 순서대로 표준 출력에 쓰는 명령  \n\n```bash\n$ cat  \naaa                     # 입력\naaa                     # 출력\nbbb                     # 입력\nbbb                     # 출력\n```\n작업 끝내고 싶다면 **ctrl + d** 누르기  \n\n### `vi 에디터로 편집 중에 ctrl + z 누른 경우`  \nprocess를 잠시 suspend 시킴 (보류)  \n\n```bash\n$ vi hello.c            # 편집 중에 ctrl + z 누른 뒤...\n[1]+    Stopped         vi hello.c  \n\n$ps\n  PID  TTY          TIME CMD\n20145  pts/11    0:00:00 bash\n23919  pts/11    0:00:00 vi\n27662  pts/11    0:00:00 ps\n\n$ jobs\n[1]+    Stopped         vi hello.c \n```  \n\n### `Stopped 시킨 job으로 돌아가기`  \n**fg** = background 작업을 foreground로 옮기기\n```bash\n$ fg %1             # 1번 작업인 vi 에디터로 다시 돌아감  \n```\n\n### `(sleep 1000 ; echo \"pcc001 - 1000sec\") \u0026`  \n* 프로그램 실행 시에 끝에 \u0026를 붙여 백그라운드로 실행시킬 수 있다.  \n* jobs 명령을 통해 현재 백그라운드에서 동작하고 있는 프로그램의 확인이 가능하다.  \n* 백그라운드 프로그램을 죽이고 싶다면 **kill -9 %번호**\n\n```bash\n$ sleep 1000 ; echo \"pcc001 - 1000sec\" \u0026            # 앞 작업이 끝나야 뒤 작업 실행되므로 제대로 작동하지 않음\n$ (sleep 1000 ; echo \"pcc001 - 1000sec\") \u0026          # 묶어주면 background 작업으로 작동함\n```\n\n### `cat a.out`  \n* a.out는 우리가 읽을 수  있는 텍스트 파일이 아니고 binary 파일이다.  \n따라서 cat a.out 실행시 읽을 수 없는 내용이 보여진다.  \n* hello.c는 C source, ASCII text 파일이므로 cat hello.c 명령어 실행시 파일 내용을 보여준다.  \n\n### `cat`  \n* concatenate files and print on the standard output  \n* 파일을 합쳐서 statndard output으로 보여주는 명령어  \n* ctrl + d 누르면 cat 프로그램 종료, (EOF)\n\n```bash\n$ cat\naaa                 # 파일이 없다면 statndard input을 입력으로 받아서\naaa                 # standard output에 출력한다.  \n```\n* 터미널 사용할 때 기본 입력장치: 키보드, 기본 출력장치: 모니터  \n* 버퍼 종류 중에 대표적인 것: 한줄씩 보내줌.\n    * stdin으로 aaa 엔터 입력 -\u003e CPU가 처리 -\u003e stdout으로 한줄 내보냄.\n\n### `redirection`  \n* `\u003c file` : stdin 대신에 이 파일을 쓰세요\n* `0\u003c file` : \u003c file 과 동일\n* `\u003e file` : stdout 디바이스(/dev/pts/8)로 나갈 것을 file에 써주세요.  \n* `1\u003e file`: \u003e file과 동일  \n* `2\u003e file`: stderr를 이 file로 내보내주세요.  \n\n### `date`  \n현재의 시간과 날짜를 stdout에 출력해주는 명령어  \n\n```bash\n$ date \u003e date.txt           # stdout이 date.txt 파일로 리디렉션됨.  \n$ cat date.txt\n2022. 01. 05 (수) 16:02:23 KST  \n\n$ cat date.txt hello.c output.txt \u003e total.txt            \n# 파일 3개가 total.txt로 concatenate됨.\n$ cat hello.c hello.c hello.c \u003e hello3                   \n# hello.c 3개가 hello3에 합쳐짐  \n\n$ cat \u003c hello3                                             \n# input으로 hello.c를 받아서 stdout에 출력함.\n$ cat hello3                                               \n# cat \u003c hello3와 동일  \n\n$ cat \u003c hello3 \u003e hello4\n$ diff hello3 hello4        # 두 파일은 동일한 파일이다.  \n\n$ cat hello.c hello.cpp 1\u003eout.txt 2\u003eerr.txt \n# hello.c 내용을 받아 stdout이 out.txt에 저장됨. hello.cpp 파일이 없어 발생한 에러 메세지는 err.txt에 저장된다.  \n```  \n\n### `stdin, stdout, stderr redirection`  \nin.txt 파일에는 학번(201921085)이 저장되어있고 아래 코드는 hello.c 파일이다.\n\n```c\n#include \u003cstdio.h\u003e\n\nint main()\n{\n    int in_a;\n    fscanf(stdin, \"%d\", \u0026in_a);\n    fprintf(stdout, \"Hello stdout %d\\n\", in_a);\n    fprintf(stderr, \"Hello stderr %d\\n\", in_a);\n}\n```\n\n```bash\n./a.out \u003c in.txt \u003e out.txt 2\u003eerr.txt\n```\n\n위 명령어 실행시 out.txt에는 Hello stdout 201921085가, err.txt에는 Hello stderr 201921085가 저장된다.  \n`\u003e\u003e` 는 계속 내용이 누적되도록 할 수 있다.  \n\n***\n\n## Lecture 3  \n\n##### - 2022. 01. 06  \n\n### `linux command`\n\n교수님의 코드를 카피하였더니 프롬프트가 초록색으로 변경되었다. (색 지정 O)  \n\n```bash\ncp ~hwan/.profile  ~hwan/.bashrc  ~hwan/.bash_logout ~\nsource .profile\n```  \n\n### `which`  \n* 특정 명령어의 위치를 찾아주는 명령어  \n* which 명령어를 사용하면 현재 사용하고 있는 명령어 실행파일의 위치를 알 수 있다.\n\n### `grep`  \n텍스트 파일에서 원하는 문자열이 들어간 행을 찾아 출력하는 명령어  \n\n### `ls`  \nls 명령어가 처음에 위치해 있는 곳은?? **storage**, storage에 들어있는 것은 파일이다.  \n\n```bash\n$ which ls\n/bin/ls\n```  \n\n### `PATH`  \n\n```bash\n$ vi ls             # ls에는 ls -lida 저장함\n$ chmod +x ls\n$ ./ls              # 직접 작성한 ./ls 실행됨\n$ ls                # /bin/ls의 ls가 실행됨\n```  \n\n* 시스템 안에 존재하는 ls 중 무엇을 실행시킬지 순서를 정해야함: 환경변수 **PATH**  \n\n```bash\n$ echo $PATH\n/home/course/pcc039/bin:/home/course/pcc039/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:.\n```  \n\n* source .profile을 통해 마지막줄 PATH=\"$HOME/bin:$HOME/.local/bin:$PATH:.\"이 실행되어 path가 추가되었다.\n\n* 따라서 lec02에 있는 a.out를 ./a.out으로 실행했어야 했는데 path를 추가한 뒤에는 a.out으로 실행시킬 수 있다.  \n\n```bash\n$ which a.out\n./a.out                         # 현재 디렉토리 밑에 있는 a.out이 실행된다.\n```  \n\n_그래도 .을 빼는 것이 보안상 안전하다..!_  \n\n### `Markdown`  \n\n* `#`: 제목\n* `##`: 부제목\n* `###`: 부부부제목  \n* 문단을 나누고 싶을 때는 빈 줄을 한줄 더 만들기  \n* `*` 또는 `1. `: 목록 또는 숫자 붙은 목록이 만들어진다.\n    * 계속 1. 로 적어도 자동으로 1, 2, 3 순서대로 숫자 붙여준다.\n\n* git.ajou.ac.kr 에서 마크다운 language를 사용하여 README.md 수정한 뒤 commit message를 쓰고 commit 하였다.  \n\n\u003e 마크다운 공부하려면 Markdown 클릭! [Markdown](https://www.youtube.com/playlist?list=PLKseYrrlvWNpYJxtfoUj5FLuMHv7Wrmid)  \n\n### `주의할 점`  \n\n* 코드로 쓰는 쌍 따옴표, 단 따옴표와 MS word가 바꾸는 코드는 다르다..!\n* MS word에서는 ASCII 코드가 아니라 유니코드임  \n\n\u003cdiv style=\"text-align : center;\"\u003e\n    \u003cimg src=./img/echo.png width=\"50%\" \u003e  \n\u003c/div\u003e  \n\n### `gitignore`  \n\n* git.ajou.ac.kr에서 내 폴더로 들어간 뒤 new file을 추가함  \n* template type을 .gitignore로 선택한 뒤, binary 파일을 git 서버에 백업하지 않도록 아래와 같이 작성하고 commit 하였다.\n\n```bash\n*.out\n```  \n\n### `clone`  \n* clone with https를 눌러 링크를 복사한 뒤 ssh 서버의 pcc 디렉토리에 git clone https://git.ajou.ac.kr/kwaksj329/pcc001.git 으로 clone 하였다.  \n\n* pcc001 디렉토리 안에는 .git과 .gitignore 와 같은 hidden file과 README.md가 있다.  \n\n* . 으로 시작하는 파일은 hidden 파일이다.  \n\n```bash\n$ file * .*             # 모든 파일과 hidden 파일\nREADME.md:  UTF-8 Unicode text  \n.:          directory\n..:         directory\n.git        directory\n.gitignore:  ASCII text\n```\n\n.gitignore는 한글이 하나도 포함되어 있지 않기 때문에 ASCII text이다.  \n\n### `clear`  \n터미널 내용을 지우고 싶을 때 사용하는 명령어  \n\n### `unicode`  \nunicode는 1바이트, 2바이트, 4바이트, 8바이트로 이루어져 있다.  \n한글을 쓰려면 unicode, UTF-8 을 써야한다.  \n\n### `git 프로젝트를 전체 프로젝트로 만들기`  \n\n1. lec01 \u0026 lec02 를 pcc001로 옮기기  \n2. pcc001에 있는 모든 파일을 pcc 디렉토리 밑으로 옮기기  \n    * 아래 코드는 2번 방법에 해당함\n\n```bash\n$ mv pcc001/* .                 # pcc 디렉토리에 hidden 파일은 안옮\n$ mv .git .gitignore ..         # pcc 디렉토리로 옮김\n```  \n\n### `ssh \u0026 https`  \n\n* git-scm 설치\n* git-bash 실행시 가상의 터미널이 열림 -\u003e 터미널이 열리자마자 bash가 실행됨\n* ssh 프로그램 실행시켜 git.ajou.ac.kr 접속함 =\u003e 터미널로 들어온 것은 `ssh` 서비스라고 함  \n* 웹브라우저로 git.ajou.ac.kr로 접속함 =\u003e `https` 서비스로 접속함\n\n### `pipe`  \n어떤 출력을 다음에 오는 명령어의 입력으로 넣는 명령어  \n\n```bash\n$ ps -ael | grep ssh            # ps -ael의 출력 중 ssh를 찾는 명령어\n$ who | wc                      # who 결과의 라인수, 단어수, 글자수 세어줌\n\n$ wc\naaa bbbb cccc\n1   3   15                      # 1글자, 3단어, 15글자 (글자 + 줄바꿈까지)\n\n$ grep aaa                      # 파일 없이 standard input을 받아 해당 string이 나타나면 표시해줌  \n$ grep printf hello.c | wc      # hello.c 파일의 printf 찾아 라인수, 단어수, 글자수 세어줌\n```  \n\n**Q**) 파이프는 어디에 있을까?  \n\u003e buffer, output buffer를 input buffer에 symbolic link 시켜둠  \n파이프는 메모리에 버퍼 형태로 존재하며 파이프도 디바이스기 때문에 /dev/에 디파이스 파일로 만들 수 있다.  \n\n* 파이프를 자료구조로 생각하면 queue이다. (FIFO)\n* 따라서 파이프 만드는 명령어 `mkfifo mypipe`  \n* 파이프는 파일의 속성이 **p**이다!  \n\n```bash\n$ mkfifo mypipe\n```\n\n### `tee`  \nstdin을 받아서 stdout과 하나 이상의 파일에 그 입력을 출력하는 명령어\n\n\u003cdiv style=\"text-align : center;\"\u003e\n    \u003cimg src=./img/tee.png width=\"70%\" \u003e  \n\u003c/div\u003e  \n\n```bash\n$ echo testing | tee test.txt\ntest\n$ cat test.txt\ntest\n\n$ ls -l | tee aaa           # ls -l의 결과가 stdout에도 출력되고 aaa에도 저장된다. \n```  \n\n### `git 서버에 올리는 방법`  \n\n```bash\n$ git pull                  # 혹시 서버에서 update 한게 있다면 가져와 merge 함\n$ git add *\n$ git commit -m \"Added something\"\n$ git push\n```  \n\n* git commit만 치면 nano editor가 실행된다.  \n* vi ~/.gitconfig 파일에 아래 코드를 추가하면 nano 에디터가 아닌 vi 에디터가 실행된다.  \n    * git commit 실행 후 파일에 commit message 적어서 저장해주면 commit message가 설정된다.  \n\n```bash\n[editor]\n    editor = vi\n[color]\n    ui = auto\n```\n\n* 내 PC 에서 git bash 실행하여 Desktop/new_folder로 이동한 다음 git clone 해옴  \n* 내 PC 에서도 파일을 수정하고 git add, git commit, git push 가능!  \n\n***\n\n## Lecture 4  \n\n##### - 2022. 01. 10  \n\n### `pipe`  \n\n* standard I/O는 기본적으로 메모리에 들어있다.  \n* 그 메모리에 구성되어있는 디바이스는 /dev/stdin, /dev/stderr, /dev/stdout, /dev/fd 에 있다.  \n* 추가로 사용자가 3, 4, 5 ... 도 만들어서 stdin이나 stdout으로 내보낼 수 있다.  \n\n\u003cdiv style=\"text-align : center;\"\u003e\n    \u003cimg src=./img/stdio.png width=\"70%\" \u003e  \n\u003c/div\u003e  \n\n### `redirection`  \n\n* `\u003c` == `0\u003c`  : 파일로부터 표준 입력을 받도록 redirection\n* `\u003e` == `1\u003e`  : stdout의 출력을 파일의 출력으로 redirection\n* `\u003e\u003e` == `1\u003e\u003e`  :stdout의 출력을 파일에 내용 추가 (append)\n* `2\u003e`  : stderr의 출력을 파일의 출력으로 redirection\n* `2\u003e\u003e`  : stderr의 출력을 파일에 내용 추가 (append)  \n\n```bash\n$ echo hello \u003e /tmp/out\n$ \u003e /tmp/out echo hello             \n$ echo \u003e /tmp/out hello                 # 순서 바꿔도 상관 없음\n$ echo hello \u003e\u00262\n$ echo \u003e\u00262 hello                        # stdout을 stderr로 내보냄\n$ read -r line \u003c file            \n$ \u003c file read -r line\n```  \n\n```bash\n$ mycomm \u003e outfile 2\u003e\u00261 을 줄여서 mycomm \u0026\u003e outfile\n$ mycomm \u003e\u003e outfile 2\u003e\u00261 을 줄여서 mycomm \u0026\u003e\u003e outfile\n$ mycomm1 2\u003e\u00261 | mycomm2 을 줄여서 mycomm1 |\u0026 mycomm2\n```  \n\n```bash\n$ a.out \u003c\u003c\u003c 300 \u0026\u003e out.txt\n$ more out.txt\nHello stderr 300\nHello stdout 300\n```\n\n**Q**) 코드는 stdout -\u003e stderr 순서로 작성했는데 왜 out.txt에는 반대 순서로 저장되어 있을까?  \n\u003e stdout에서 stdout device로, 그리고 stderr에서 stderr device로 나가는 순서는 누가 먼저 나갈지 아무도 모름!  \n만약 stdout 먼저 나가게 하고 싶다면 stdout buffer에 쓰고 flush 명령으로 버퍼 비우게 해야함. 그 다음에 stderr buffer에 쓰고 stderr device에 내보내야 순서대로 저장된다.  \n\n* 리디렉션 공부시 참고! [Redirection](https://mug896.github.io/bash-shell/redirections.html)  \n\n### `here document, here string`  \n\n* `here document`\n* `\u003c\u003c` == `0\u003c\u003c`  : 임시 파일을 만들어 stdin으로 연결  \n\n```bash\n$ cat \u003c\u003cEOF         # EOF 라고 타이핑하기 전까지는 계속 입력을 받으세요.\n\"200\"\nEOF                 # 입력 끝냄\n\"200\"\n```  \n\n```bash\n$ cat \u003c\u003cQQQ\n\u003e 200\n\u003e Hi\n\u003e Print\n\u003e QQQ               # 입력 끝냄\n200\nHi\nPrint\n```\n\n* `here string`\n* `\u003c\u003c\u003c`  : string을 stdin 입력으로 연결 (bash only)\n\n```bash\n$ cat \u003c\u003c\u003c $( echo -e \"hello\\nhere        string\" )          \n# $ == 명령어 실행한 결과\nhello\nhere        string\n\n$ cat \u003c\u003c\u003c *               # globbing 이 발생하지 않는다.\n*\n```\n\n```c\n//hello.c 파일\n#include \u003cstdio.h\u003e  \n\nint main()\n{\n    int in_a;\n    fscanf(stdin, \"%d\", \u0026in_a);\n    fprintf(stdout, \"Hello stdout %d\\n\", in_a);\n    fprintf(stderr, \"Hello stderr %d\\n\", in_a);\n}\n\n```\n\n```bash\n$ cc hello.c            # hello.c 컴파일하여 a.out 실행파일 생성됨.\n$ a.out \u003c\u003c\u003c 99          # here string, bash에서만 가능!\nHello stdout 99\nHello stderr 99\n```\n\n### `pipe order of execution`  \n\n`$ cmd1 | cmd2`  \n* cmd1 과 cmd2 는 동시에 병렬로 실행된다.  \n\n* cmd1 이 cmd2 보다 빠르면 파이프에 write 은 블록되고 더이상 진행되지 않는다.  \n\n* cmd2 가 cmd1 보다 빠르면 파이프 로부터의 read 는 블록된다.  \n\n* cmd1 이 먼저 종료하면 파이프는 close 되고 cmd2 는 End-Of-File 로 인식해 종료한다.  \n\n* cmd2 가 먼저 종료하면 파이프는 close 되고 cmd1 은 다음번 write 에 SIGPIPE 신호를 받게되고 종료된다. (파이프가 깨졌다는 신호)  \n\n**Q**) cmd1 이 cmd2 보다 빠르면 파이프에 write 은 블록되고 더이상 진행되지 않는 이유?  \n\u003e stdin buffer와 stdout buffer 둘다 1024 바이트일 때, stdin이 stdout 보다 느린 경우 stdout을 안가져가면 버퍼가 꽉차서 stdout에 더 이상 내보내면 안된다.  \n버퍼가 꽉 차있는데 내보내면 버퍼 플로우가 일어나서 데이터를 잃게 된다.  \n\n**Q**) cmd2가 cmd1보다 빠른 반대의 경우에는?\n\u003e cmd2 이 cmd1 보다 빠르면 파이프에 read 은 블록되고 더이상 진행되지 않는다.  \n\n### `named pipe`  \n\n* Pipe는 자동으로 생성 / 소멸\n* Named Pipe\n    * mkfifo 명령으로 생성 – 파일처럼 생성됨 \n    * redirection으로 sending\n* 읽는 상대편이 없으면 Block 된다\n* Buffer Control 이 필요\n\n### `globbing, wild card`  \n\n* glob 문자에 의해 매칭된 파일들로 치환되는 것: globbing\n* \\* = 없는 것을 포함하여, 어떠한 수의 문자라도 일치\n* ? = 어떤 한 문자를 일치\n* [abc] = 대괄호 안의 하나의 문자를 일치\n* [a-c] =  대괄호 안의 범위에 속하는 하나의 문자를 일치  \n\n```bash\n$ echo h*           # h로 시작하는 파일 보여줌\nhello.c\n$ echo *.c\nhello.c\n$ echo ?????        # 5글자 파일 보여줌\na.out\n$ echo ?????*       # 5글자 넘는 파일 보여줌\n$ echo [abc]*       # a/b/c로 시작하는 파일 보여줌\n$ echo [a-q]*       # a~q로 시작하는 파일 보여줌\n```  \n\n### `b.out | a.out`  \n\n```c\n//hello.c               # a.out 실행파일\n#include \u003cstdio.h\u003e\n\nint main()\n{\n    int in_a;\n    fscanf(stdin, \"%d\", \u0026in_a);\n    fprintf(stdout, \"Hello stdout %d\\n\", in_a);\n    fprintf(stderr, \"Hello stderr %d\\n\", in_a);\n}\n```\n\n```bash\n$ vi hello2.c               # input을 받아 stdout으로 숫자 내보내는 코드 작성\n$ cc -o b.out hello2.c\n$ b.out | a.out             # b.out의 출력이 a.out의 입력으로 들어가 실행됨\n999\nHello stdout 999\nHello stderr 999\n```\n\n### `named pipe`  \n\n```bash\n# 첫번째 터미널에서..\n$ mkfifo pipe\n$ b.out \u003e pipe\n99\n\n# 동시에 두번째 터미널에서..\n$ ./a.out \u003c pipe        # pipe에 담긴 99 읽어와서 실행 + 출력\nHello stdout 99\nHello stderr 99\n```  \n\n_pipe: a.out라는 프로그램과 b.out라는 프로그램, 두 프로그램 사이에서 통신하는데 사용 가능_   \n\n**대표적으로 두개의 process 간의 통신하는 방식: pipe**  \n\n### `vi pipe`\n\n```bash\n$ vi pipe           # vi 에디터로 pipe 열어서 12345 저장함\n$ cat \u003c pipe        # pipe에 저장한 것 보여준다\n12345\n```\n\n### `basic data type`  \n\n```c\nint ifuncAdd(int a, int b)\n{\n    return a+b;\n}\n```\n\n**Q**) 여기서 a, b는 정수이다 -\u003e [ X ]\n\u003e 정수는 -무한대 ~ 무한대이기 때문에 a, b는 정수형이다. (정수 타입)  \n\n**Q**) int가 4바이트라고 표준화 기구가 정했다 -\u003e [ X ]  \n\u003e 기계에 따라 다르다. 어떤 기계에서는 4바이트, 8바이트, 2바이트로 달라진다.  \n\n**위 코드는 이 컴퓨터와 컴파일러에서 정희한 정수형 데이터타입이 허용하는 범위 내의 a, b를 합하여 니온 결과가 다시 한번 허용하는 정수 범위 내에 있어야한다.**\n\n* int: 4바이트, 2바이트, 8바이트, 1바이트\n* char, unsigned char: 1바이트, 2바이트\n\n* Standard signed integer type\n    * signed char, short int, int, long int, long long int\n* Unsigned\n    * unsigned ...\n* floating type\n    * flout, double, (long double) \n* Definition in standard\n    * char - large enough to store any execution character set\n    * 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.\n    * Complex\n    * Bool - 0,1을 저장하면 된다. (따라서 일반적으로 int형 사용)  \n    * void - char의 포인터라고 생각하면 쉽다.  \n\n* c언어에서 half float (2byte), float (4byte) double (8byte) long double(16byte)로 몇 바이트인지 정의하고 있지 않다. \n\n* 대신 half float ⊆ float ⊆ double ⊆ long double처럼 부분집합 (subset)으로 정의하고 있다.\n\n### `Negative integer`  \n\n`음수 표현 방법 3가지`  \n\n* signed bit + value  \n* two's complement: -를 곱하고 +1\n* one's complement: not (bitwise)  \n\n* C 언어에서는..? 음수를 표현하기 위해 위 3가지 경우 중 하나 사용하면 된다.  \n\n### `signed \u0026 unsigend`\n\n* signed \u0026 unsigend: noun-adjective format  \n* 그래서 int나 char같은 타입 앞에 signed / unsigend를 쓴다.\n\n### `(터미널에서) python 사용`  \n\n```bash\n$ python\n$ bin(-4)\n'-0b100'\n$ bin(-7)\n'-0b111'\n```\n\n* python의 integer\n    * 2 ** 32, 2 ** 64, 2 ** 1024... 표현 가능\n    * 따라서 python의 integer는 크기의 제한이 없다.\n\n* python에서는 음수 표현할 때 대부분 two's complement를 사용한다.\n\n### `limits.h`\n\n* /usr/include/limits.h에 타입과 그 크기가 정의되어 있다.\n* Maximum length of any multibyte character in any locale.\n    * define MB_LEN_MAX     16 \n    * = 이 컴퓨터에서는 multibyte character 16 바이트보다는 크지 않아야한다.\n\n**limits.h는 기계마다, 컴파일러마다 다르다!**\n\n### `10진수를 2진수로 출력해주는 코드`\n\n```c\n//binary.c\n# include \u003cstdio.h\u003e\n\nint main()\n{\n    int i;\n    int in_a;\n    fscanf(stdin, \"%d\", \u0026in_a);\n    for (i = 31 ; i \u003e= 0 ; i--){\n        \n        fprintf(stdout, \"%d\", ((in_a\u003e\u003ei) \u0026 1));\n        if (i % 4 == 0)\n            fprintf(stdout, \" \");\n    }\n    fprintf(stdout, \"\\n\");\n}\n```\n```bash\n$ cc -o bin binary.c\n$ bin \u003c\u003c\u003c 3\n0000 0000 0000 0000 0000 0000 0000 0011\n```\n\n* int 형 변수 in_a 를 입력받아 shitf 연산을 한 후에 1과 \u0026(and) 연산을 하여 2진수로 변환하여 출력하는 코드이다.\n* `\u003e\u003e` 는 right shift이고 나누기 2와 같다.\n* `\u003c\u003c` 는 left shift이고 곱하기 2와 같다.\n\n### `음의 10진수 \u003c-\u003e 2진수 변환 방법`  \n\n* 음의 10진수 정수를 2진수로 바꾸고 싶을 때\n    1. 해당 정수를 양수로 바꾸어 2진수로 표현한 후, \n    2. 구한 2진수에서 1은 0으로, 0은 1로 바꾼 다음,\n    3. 1을 더한다.\n\n* 2진수를 음의 10진수 정수로 바꾸고 싶을 때\n    1. 2진수에서 1은 0으로, 0은 1로 바꾼 다음,\n    2. 바꾼 2진수에서 1을 더하고\n    3. 더한 2진수를 10진수로 변환하여, 음을 붙인다.\n\n\u003cdiv style=\"text-align : center;\"\u003e\n    \u003cimg src=./img/twos.png width=\"65%\" \u003e  \n\u003c/div\u003e  \n\n* 사진에서 위의 식은 2진수를 양의 10진수로, 아래 식은 음의 10진수로 변환하는 식이다.\n\n* 00000000 = 0 (10진수)\n* 00000001 = 1 (10진수)\n* 00000010 = 2 (10진수)\n* 10000000 = -128 (10진수)\n* 10000001 = -127 (10진수)\n* 11111111 = -1 (10진수)\n* 11111110 = -2 (10진수)\n\n### `python과 bin에서의 정수형`\n\n* python에서는..\n\n```bash\n$ bin(3)\n'0b11'\n$ bin(-3)\n'-0b11'\n```\n\n* 우리가 위에서 짠 bin 프로그램에서는..\n\n```bash\n$ bin \u003c\u003c\u003c 3\n0000 0000 0000 0000 0000 0000 0000 0011\n\n$ bin \u003c\u003c\u003c -3\n1111 1111 1111 1111 1111 1111 1111 1101\n```\n\n* 우리가 짠 bin 프로그램을 바탕으로 3과 -3을 \u0026 operation하면 0000 0000 0000 0000 0000 0000 0000 0001이 나온다.\n\n* 파이썬에서도 bin(3\u0026-3)을 하면 '0b1'이 나온다.\n\n* 파이썬에는 정수형 데이터의 길이가 정해져있지 않다.\n\n* 파이썬에서는 모든 음수를 two's complement로 표현한다.\n    * 내부적으로는 bin(-3)이 '-0b11' 이렇게 bit가 표현되어 있지 않다는 뜻이다.\n\n* 파이썬에서 3은 0000000....0000011 로 앞에 0이 무한대로 있다.\n\n* 파이썬에서 -3은 11111111......1101로 앞에 1이 무한대로 있다.\n\n### `2진수의 \u0026 operation 코드`  \n\n* 앞 코드에서 in_c = in_a \u0026 in_b 추가함\n\n```c\n// binary.c\n# include \u003cstdio.h\u003e\n\nint main()\n{\n    int i;\n    int in_a, in_b, in_c;\n    fscanf(stdin, \"%d %d\", \u0026in_a, \u0026in_b);\n    in_c = in_a \u0026 in_b;\n    for (i = 31 ; i \u003e= 0 ; i--){\n        \n        fprintf(stdout, \"%d\", ((in_a\u003e\u003ei) \u0026 1));\n        if (i % 4 == 0)\n            fprintf(stdout, \" \");\n    }\n    fprintf(stdout, \"\\n\");\n\n    for (i = 31 ; i \u003e= 0 ; i--){\n        \n        fprintf(stdout, \"%d\", ((in_b\u003e\u003ei) \u0026 1));\n        if (i % 4 == 0)\n            fprintf(stdout, \" \");\n    }\n    fprintf(stdout, \"\\n\");\n\n    for (i = 31 ; i \u003e= 0 ; i--){\n        \n        fprintf(stdout, \"%d\", ((in_c\u003e\u003ei) \u0026 1));\n        if (i % 4 == 0)\n            fprintf(stdout, \" \");\n    }\n    fprintf(stdout, \"\\n\");\n    \n}\n```\n\n```bash\n$ cc -o bin binary.c\n$ bin\n100 -100                # 100과 -100의 \u0026 operation\n0000 0000 0000 0000 0000 0000 0110 0100\n1111 1111 1111 1111 1111 1111 1001 1100\n0000 0000 0000 0000 0000 0000 0000 0100\n```\n\n### `in_c = in_a \u003e\u003e 2 수정 (오른쪽으로 shift)`  \n\n* 위 코드에서 in_c = in_a \u0026 in_b를 in_c = in_a \u003e\u003e 2로 수정해보았다.\n\n```bash\n$ bin\n-456 456\n1111 1111 1111 1111 1111 1110 0011 1000\n0000 0000 0000 0000 0000 0001 1100 1000\n1111 1111 1111 1111 1111 1111 1000 1110\n```\n\n* 그리고 a, b, c를 unsigned int로 바꿔서 실행해본 결과이다.\n\n```bash\n$ bin\n-456 456\n1111 1111 1111 1111 1111 1110 0011 1000\n0000 0000 0000 0000 0000 0001 1100 1000\n0011 1111 1111 1111 1111 1111 1000 1110\n```\n\n* 위 두가지 case로 알 수 있는 점)\n\n* int 형(signed int)일 때 오른쪽으로 shift하는 경우에는 가장 왼쪽에 1이 들어간다.\n\n* 반면 unsigned int 형일 때는 오른쪽으로 shift하면 가장 왼쪽에 0이 들어간다.\n\n* 오른쪽으로 1 shift는 나누기 2와 같다. 아래 예시는 signed int 형일 때 0이 아닌 1이 가장 왼쪽에 들어가는 모습을 보여준다.\n    * 1000 0000 = -128 (10진수)\n    * 1100 0000 = -64 (10진수)\n    * 1110 0000 = -32 (10진수)\n    * 1111 0000 = -16 (10진수)\n\n* 주의해서 봐야할 점)\n\n|signed int|unsigned int|\n|:---------:|:---------:|\n|-456 = 1111 1111 1111 1111 1111 1110 0011 1000|-456 = 1111 1111 1111 1111 1111 1110 0011 1000|\n|-456을 오른쪽으로 2번 shift한 결과 1111 1111 1111 1111 1111 1111 1000 1110|-456을 오른쪽으로 2번 shift한 결과 0011 1111 1111 1111 1111 1111 1000 1110|\n\n* -456 2번 shift한 결과를 보면 signed int는 맨 앞에 11이 들어갔는데 unsigned int는 맨 앞에 00이 들어가게 되었다.\n\n**signed int일 때, 즉 맨 앞이 1이어서 음수일 때는 오른쪽으로 shift 연산이 일어나면 1이 들어간다.**  \n\n**unsigned int일 때, 즉 맨 앞이 1이지만 양수일 때는 오른쪽으로 shift 연산이 일어나면 0이 들어가게 된다.**  \n\n***\n\n## Lecture 5\n##### - 2022. 01. 11   \n\n* more: cat 과 비슷한데 다음 페이지 보고싶으면 space 키 누름\n\n* man cc -\u003e gcc가 나옴\n\n* which cc -\u003e /usr/bin/cc\n    * cc -\u003e /etc/alternatives/cc\n    * /etc/alternatives/cc -\u003e /usr/bin/gcc\n    * gcc -\u003e gcc-7\n    * gcc-7 -\u003e x86_64-linux-gnu-gcc-7\n    * x86_64-linux-gnu-gcc-7 : 이게 진짜 실행파일  \n\n* x86_64-linux-gnu-gcc-7  \n    * x86: cpu가 intel cpu 용이며, \n    * _64: intel cpu를 위한 64bit, \n    * linux: 운영체제는 리눅스를 위한,\n    * gnu gcc compiler이다.  \n\n* cpp = C preprocessor\n\n* 우리가 cc 하면 제일 먼저 cpp가 돌고, gcc compiler가 돌고, loader가 돌아서 a.out가 만들어진다.  \n\n### `unsigned int`  \n\n* binary.c 파일 아래와 같이 수정함\n\n```c\n//binary.c\n# include \u003cstdio.h\u003e\n\nint main()\n{\n    int i;\n    unsigned int in_a;\n    fscanf(stdin, \"%u\", \u0026in_a);\n    fprintf(stdout, \"%u \\t : \", in_a);\n    for (i = 31 ; i \u003e= 0 ; i--){\n        \n        fprintf(stdout, \"%d\", ((in_a\u003e\u003ei) \u0026 1));\n        if (i % 4 == 0)\n            fprintf(stdout, \" \");\n    }\n    fprintf(stdout, \"\\n\");\n}\n```\n\n* unsigned int 범위를 넘어가는 입력이나 음수를 입력받으면 입력한 수와 다른 수로 출력된다.\n    * -1 입력하면 4294967295가 출력됨. (unsigned int로)\n\n### `signed \u0026 unsigned int`\n\n* hello.c 아래와 같이 수정함 (실행파일 : a.out)\n\n```c\n//hello.c\n#include \u003cstdio.h\u003e\n\nint main()\n{\n    signed int siA;\n    unsigned int unA;\n\n    fscanf(stdin, \"%d\", \u0026siA);\n    fprintf(stdout, \"signed integer : %d\\n\", siA);\n    unA = siA;\n    fprintf(stdout, \"unsigned integer : %u\\n\", unA);\n    fprintf(stdout, \"unsigned integer percent d : %d\\n\", unA);\n    fprintf(stdout, \"signed integer percent u : %u\\n\", siA);\n\n    fscanf(stdin, \"%u\", \u0026unA);\n    fprintf(stdout, \"unsigned integer : %u\\n\", unA);\n    siA = unA;\n    fprintf(stdout, \"signed integer : %d\\n\", siA);\n}\n```\n\n```bash\n$ a.out\n-1\nsigned integer : -1\nunsigned integer : 4294967295\nunsigned integer percent d : -1\nsigned integer percent u : 4294967295\n4294967295\nunsigned integer : 4294967295\nsigned integer : -1\n```\n\n* -1이 signed integer로 저장되면 메모리 상에 1111 1111 1111 1111 1111 1111 1111 1111로 저장된다.\n\n* 따라서 저장된 데이터 1111 1111 1111 1111을 unsigned integer로 읽으면 2진수 그대로 읽어서 4294967295로 출력하게 되는 것이다.\n\n* signed int로 받은 입력 -1을 signed int 변수와 unsigned int에 저장해서 출력해보기  \n\n|signed integer|unsigned integer|\n|:-------------:|:-------------:|\n|%d로 출력하기: -1|%d로 출력하기: -1|\n|%u로 출력하기: 4294967295|%u로 출력하기: 4294967295|\n\n* 이를 통해서 signed integer 변수에 저장하거나 unsigned integer 변수에 같은 값을 저장해도 %d, %u에 따라 출력된다는 것을 알 수 있다.\n\n**unsigned 와 signed 는 bitwise 똑같은 데이터이고, bit 상태가 구분되지 않는 똑같은 데이터임을 알 수 있다.**\n\n**다만 print할 때 %d로 print하면 signed int로, %u로 print하면 unsiged int로 출력된다.**\n\n**Q**) 어떤 숫자에 unsigned integer 값을 더하면 그 값은 절대로 증가한다? [ X ]\n\u003e 오버플로우가 일어난다면 증가하지 않는다!  \n\n### `vi editor`  \n\n* yy + p : 복사 \u0026 붙여넣기\n\n* 6yy + p : 6줄 복사 후 붙여넣기\n\n* dd : 한줄 삭제\n\n* dd + p : 삭제 한 줄 붙여넣기\n\n### `signed / unsigned \u0026 int / short`  \n\n```c\n// hello.c\n// siA와 sumS는 signed int 형\n// unA와 sumU는 unsigned int 형으로 선언함\n// shortS는 signed short, ushortS는 unsigned short로 선언\n// 이전코드에서 siA를 입력받아 unA에 넣어준 상황\n\nsumS = siA + (signed int) unA;\nsumU = (unsigned int) siA + unA;\nfprintf(stdout, \"sumS %%d %d\\n\", sumS);\nfprintf(stdout, \"sumS %%u %u\\n\", sumS);\nfprintf(stdout, \"sumU %%d %d\\n\", sumU);\nfprintf(stdout, \"sumU %%u %u\\n\", sumU);\n\nshortS = siA + unA;\nushortS = siA + unA;\nfprintf(stdout, \"sumS %%d %d\\n\", shortS);\nfprintf(stdout, \"sumS %%u %u\\n\", shortS);\nfprintf(stdout, \"sumU %%d %d\\n\", ushortS);\nfprintf(stdout, \"sumU %%u %u\\n\", ushortS);\n```\n\n```bash\n$ cc hello.c\n$ ./a.out\n-1\nsumS %d -2\nsumS %u 4294967294\nsumU %d -2\nsumU %u 4294967294\nsumS %d -2\nsumS %u 4294967294\nsumU %d 65534\nsumU %u 65534\n```\n\n**Q**) 왜 실행한 결과의 마지막 2줄은 다르게 나왔을까?\n\u003e signed int와 unsigned int를 더하여 unsigned short 형 변수에 저장하였으므로 자동으로 type casting이 일어났기 때문이다.\n\n**C언어에서는 연산시에 자동으로 type casting이 일어난다.**  \n\n```c\nshortS = siA + unA;\nushortS = siA + unA;\nfprintf(stdout, \"sumS %%d %d\\n\", shortS);\nfprintf(stdout, \"sumS %%u %u\\n\", shortS);\nfprintf(stdout, \"sumU %%d %d\\n\", ushortS);\nfprintf(stdout, \"sumU %%u %u\\n\", ushortS);\n\nshortS = (short)siA + (short)unA;\nushortS = (unsigned short)siA + (unsigned short)unA;\nfprintf(stdout, \"sumS %%d %d\\n\", shortS);\nfprintf(stdout, \"sumS %%u %u\\n\", shortS);\nfprintf(stdout, \"sumU %%d %d\\n\", ushortS);\nfprintf(stdout, \"sumU %%u %u\\n\", ushortS);\n```\n\n**따라서 위 코드에서 type casting이 자동으로 일어나 같은 결과가 출력된다.**\n\n`cc -W hello.c`  \n컴파일 시 모든 것에 대해 warning을 출력하고 싶을 때 사용한다.\n\n### `count1.c - 32bit integer에서 1의 개수 세는 프로그램`  \n\n```c\n//count1.c\n#include \u003cstdio.h\u003e\n#define VALUE_ONE 1\n\n//count number of 1 (binary)\nint count_one(unsigned int a){\n\n    int count = 0;\n\n    while(a != 0){\n        count += a \u0026 VALUE_ONE;\n        a \u003e\u003e= VALUE_ONE;\n    }\n\n    return count;\n}\n\nint main()\n{\n    int i;\n    int in_a;\n    fscanf(stdin, \"%u\", \u0026in_a);\n    fprintf(stdout, \"%u \\t : \", in_a);\n    for(i = 31 ; i \u003e= 0 ; i--){\n\n        fprintf(stdout, \"%d\", ((in_a \u003e\u003ei ) \u00261));\n        if (i % 4 == 0)\n            fprintf(stdout, \" \");\n    }\n    fprintf(stdout, \": %d \\n\", count_one(in_a));\n\n}\n```\n\n* 위의 코드 설명 - 어떻게 1의 개수를 count할까?  \n\na가 10진수로 6이라면 2진수로 0000 0000 0000 0000 0000 0000 0000 0110이다.\n\n|  shift 횟수  |   a   |\n|:------:|:------:|\n|0번째|0000 0000 0000 0000 0000 0000 0000 0110|\n|1번째|0000 0000 0000 0000 0000 0000 0000 0011|\n|2번째|0000 0000 0000 0000 0000 0000 0000 0001|\n|3번째|0000 0000 0000 0000 0000 0000 0000 0000|\n\n따라서 1 (VALUE_ONE)과 a의 맨 마지막 bit 가 \u0026 연산을 하여 1의 개수를 계산하기 때문에,  \n\n1번째 shift 결과와 2번째 shift 결과에서 \u0026 연산을 통해 count에 1이 더해지게 된다.  \n\n따라서 6의 1의 개수는 2개임을 구할 수 있다.  \n\n\n### `if문의 성능`  \n\n```c\n// sol1\nif((in_a \u003e\u003e i) \u0026 1)\n    count++;\n\n// sol2\ncount += in_a \u003e\u003e i \u0026 1; \n```\n\n* C operator precedence에 따라 shift를 먼저 하고 \u0026 operation을 하기 때문에 위 \u0026 아래 코드의 연산은 같다.  \n\n* 대신 우선순위가 헷갈리기 때문에 괄호를 사용하는 것을 추천한다.\n\n* sol1과 sol2의 실행결과는 같은데 실행속도는 sol2가 빠르다.  \n    * if문은 굉장히 느리다. if문은 굉장히 비싼 operation이다.  \n\n```c\nc = a \u003e\u003e 1 + b;          //case 1\nc = (a \u003e\u003e 1) + b;        //case 2\nc = a \u003e\u003e (1 + b);        //case 3\n```\n\n* shift 연산이 곱하기 / 나누기와 우선순위가 같다고 오해할 수 있다. 하지만 shift 연산은 더하기와 빼기보다 우선순위가 낮다.\n\n* case 1의 결과는 case 2가 아닌 case 3과 같다!\n\n* 따라서 case case 1처럼 코드를 작성하고 a의 shift가 먼저 일어날 것이라고 오해할 수 있으므로, 헷갈리지 않도록 괄호를 사용하는 것을 권장한다.\n\n### `Three basic memory model in C`  \n\n* signed / unsigned 는 int와 같은 자료형의 앞에 붙는다.  \n\n* 나머지 수식은 자료형의 뒤에 붙는다. (ex - const, auto, static)  \n    * ex- int const\n\n* `Automatic` : automatic 변수는 현재 블록이 끝나면 자동으로 사라지는 변수이다.  \n    * int 이렇게 선언하면 automatic이다.  \n    * 처음 사용할 때 변수를 선언한다.\n    * 범위를 벗어날 때 제거된다.  \n\n* `Static` : static 변수는 선언된 함수 내에서만 사용이 가능하며, 단 한번만 초기화를 하고 프로그램이 종료될 때까지 메모리 공간에 존재하는 변수이다.  \n    * 프로그램이 실행되는 동안 같은 공간에 존재한다.  \n    * Array sizes는 고정되지만 values는 변경 가능하다.  \n    * main 시작전에 데이터가 초기화된다. 따라서 계산을 필요로 하지 않는 상수를 사용하여 초기화해야 한다.  \n    * static 키워드로 함수 밖에서 선언된 variables (in file scope)와 함수 안에서 선언된 variables는 static이다.  \n    * static variable을 초기화 하지 않으면, zeros (or NULL)로 초기화된다.  \n\n* `Manual`  \n    * manual type에는 malloc과 free가 포함된다.  \n    * manual type만 array의 크기가 선언 이후에도 조정할 수 있다.  \n\n### `Noun-Adjective Form`  \n\n* `int const A` constant integer  \n    * const가 뒤에서 앞으로 int를 수식함\n\n* `int const * A ` (variable) pointer to a constant integer \n    * const가 int를 수삭한다. A는 const int를 가리키는 포인터이다.\n\n* `int * const A` constant pointer to a (variable) integer \n    * int를 가리키고 있는 포인터인데 그 포인터가 const이다.\n\n* `int * const * A` pointer to a constant pointer to an integer  \n    * int를 가리키는 const 포인터를 가리키는 포인터, 이 포인터 값은 변할 수 있다.\n\n* `int const * * A` pointer to a pointer to a constant integer  \n    * const int를 가리키는 포인터의 포인터, 두 포인터 다 변경될 수 있다.\n\n* `int const * const * A` pointer to a constant pointer to a constant integer \n    * const int를 가리키는 const 포인터의 포인터\n\n**Q**) `double (*f[10])(int const *a, double (*g[10])(double h));`의 의미는?  \n\n* 함수 이름이 f인 함수를 선언하였으며 이 함수는 double을 리턴한다.  \n\n* 함수 f는 크기가 10인 포인터의 array이며 첫번째 parameter는 int const 형태의 포인터 a이다.  \n\n* 두번째 parameter는 함수 이름이 g이고 크기가 10인 포인터의 array이다.\n\n* g 함수는 double을 리턴하며, double을 리턴하는 상수 h를 parameter로 가진다.  \n\n### `static 변수 예시`  \n\n```c\n//count1.c\n#include \u003cstdio.h\u003e\n#define VALUE_ONE 1\n\n//count number of 1 (binary)\nint count_one(unsigned int a){\n\n    int static numCalls = 0;\n    int count = 0;\n\n    while(a != 0){\n        count += a \u0026 VALUE_ONE;\n        a \u003e\u003e= VALUE_ONE;\n    }\n\n    fprintf(stderr, \"Call : %d\\n\", numCalls);\n    numCalls++;\n\n    return count;\n}\n\nint main()\n{\n    int i;\n    int in_a;\n    fscanf(stdin, \"%u\", \u0026in_a);\n    fprintf(stdout, \"%u \\t : \", in_a);\n    for(i = 31 ; i \u003e= 0 ; i--){\n\n        fprintf(stdout, \"%d\", ((in_a \u003e\u003ei ) \u00261));\n        if (i % 4 == 0)\n            fprintf(stdout, \" \");\n    }\n    count_one(in_a);\n    count_one(in_a);\n    count_one(in_a);\n    count_one(in_a);\n    fprintf(stdout, \": %d \\n\", count_one(in_a));\n\n}\n```  \n\n* count_one 함수의 parameter로 signed int를 받게 되면 무한루프에 빠질 수 있다.  \n    * a가 signed int형 변수이고, 음수 데이터가 저장되어 있을 때, 오른쪽으로 shift를 계속해도 0이 되지 않고 계속 1이 채워지기 때문에 while문에서 무한루프에 빠지게 된다.  \n    * a가 unsigned int 형이면 오른쪽으로 shift할 때 맨 왼쪽에 0이 채워지게 되고, 그럼 while문 안에서 shift가 반복해서 일어나면 언젠가 a가 꼭 0이 된다.\n    * 따라서 입력이 음수일 때 무한루프에 빠지지 않기 위해서 count_one 함수의 parameter를 unsigned int a라고 선언해야한다.\n\n* count_one을 4번 호출한 결과로 아래와 같이 출력된다.  \n\n```\nCall: 0\nCall: 1\nCall: 2\nCall: 3\nCall: 4\n```\n\n* numCalls 변수가 int 형 변수라면 모두 0이 나왔겠지만, int static 변수이기 때문에 0, 1, 2, 3, 4가 출력되었다.  \n\n* numCalls 변수가 static 변수이기 때문에 한번만 초기화하고, 프로그램이 종료될 때까지 메모리 공간에 계속 존재하기 때문에 0으로 초기화되지 않고 값을 누적해서 출력한 것을 볼 수 있다.\n\n* static 변수는 초기화하지 않으면 자동으로 0 (또는 NULL)으로 초기화 되지만 automatic 변수는 초기화하지 않고 값을 출력해보면 랜덤한 값이 출력된다.  \n\n### `define`  \n\n* preprocessor는 반복되는 값이나 작업을 미리 정의할 때 사용하며, preprocessor에서 #define으로 매크로를 정의할 수 있다.  \n\n* #define 매크로이름 값 : 이렇게 매크로를 정의할 수 있다.  \n\n* 이러한 매크로를 사용하면 preprocessor를 거쳐 내부적으로 소스 코드가 일괄 변환되게 된다.\n\n### `const`  \n\n* const 변수는 값을 변경할 수 없다. 변수가 상수임을 선언하는 예약어이다.\n\n* 상수는 반드시 선언과 동시에 값을 할당하여 초기화해주어야 하며 초기화를 하지 않으면 컴파일 에러가 발생한다.\n\n```c\nint const con = 100;\ncon++;\n```\n\n* const 변수로 선언된 값은 변경이 불가능하므로 컴파일 time에 에러가 난다! ( increment of read-only variable 'con' )\n\n***\n\n## Lecture 6\n##### - 2022. 01. 12   \n\n### `.bash_logout`  \n\n```bash\nif [ \"$SHLVL\" = 1 ]; then\n    [ -x /usr/bin/clear_console ] \u0026\u0026 /usr/bin/clear_console -q\nfi\nclear\nclear\necho HAVE a NICE DAY - I am Sujong Kwak\n```  \n\nlogout 시에 clear 명령으로 터미널 명령을 지우고, echo로 원하는 문장을 출력하도록 하였다.  \n\n### `alias`  \n\nalias = bash에 들어있는 built in 명령이다.  \n\n```bash\n$ alias -p\nalias alert='notify-send --urgency=low -i \"$([ $? = 0 ] \u0026\u0026 echo terminal || echo error)\" \"$(history|tail -n1|sed -e '\\''s/^\\s*[0-9]\\+\\s*//;s/[;\u0026|]\\s*alert$//'\\'')\"'\nalias cc='cc -Wall'\nalias egrep='egrep --color=auto'\nalias fgrep='fgrep --color=auto'\nalias grep='grep --color=auto'\nalias h='history'\nalias l='ls -CF'\nalias la='ls -A'\nalias ll='ls -alF'\nalias ls='ls --color=auto'\n```\n\n* alias cc='cc -Wall' 을 통해 cc 명령어 실행시 자동으로 cc -Wall 명령으로 바뀌도록 할 수 있다.  \n\n* alias를 풀고 싶다면 unalias cc 사용  \n\n* 만약 alias를 사용하고 싶지 않다면 back slash('\\')를 사용한다.  \n\n```bash\n$ ls            # alias 사용\n$ \\ls           # alias 사용 X\n```\n\n* 로그아웃하면 없어지기 때문에 ~/.bashrc 에 alias 를 추가해야한다.  \n\n* source ~/.bashrc 로 실행하면 적용된다.\n\n### `오늘의 목표 - Pointer 이해하기`  \n\n* pointer basic\n    * \u0026val - Address of val\n    * *ptr - Value in address val\n\n* increment\n    * int *a;       //a++ increment by 4\n        * a = integer를 가리키는 주소\n    * long long *b; //b++ increment by 8\n        * b = long long을 가리키는 주소\n    * void *c;      //c++ increment by 1\n\n### `\u0026\u0026 와 ;`\n\n```bash\n$ cc hello.c \u0026\u0026 a.out       #1\n$ cc hello.c ; a.out        #2\n```\n\n첫번째 명령은 hello.c가 에러가 나지 않을 때만 a.out가 실행되는 반면에,  \n두번째 명령은 hello.c가 에러나도 a.out가 항상 실행된다.  \n\n* 앞이 오류나지 않았을 때만 뒤 명령어 실행하고 싶다면 -\u003e 명령어1 \u0026\u0026 명령어2  \n\n* 앞이 오류났을 때 뒤 명령어를 실행하고 싶다면 -\u003e 명령어1 || 명령어2  \n\n### `hello.c - a와 b의 주소`  \n\n```c\n#include \u003cstdio.h\u003e\n\nint main()\n{\n    int a = 100;\n    int b = 200;\n    fprintf(stdout, \"%d : %d\\n\", a, \u0026a);    // 100 : 1893560592\n    fprintf(stdout, \"%d : %d\\n\", b, \u0026b);    // 200 : 1893560596\n}\n```\n\n* a의 주소에서 int형 변수의 크기인 4바이트 떨어진 곳에 b가 위치한 것을 알 수 있다.  \n\n* int * -\u003e long long -\u003e lld로 출력하기! 16진수로 보고싶다면 llx로 출력한다.  \n\n* a와 *\u0026a는 같다. *\u0026a에 값을 넣을수도 있다. ( *\u0026a = 500; )\n\n**Q**) 어떤 사람은 주소 결과가 음수로 나왔는데 왜일까?\n\u003e 메모리 주소 길이가 오버플로우 났기 때문이다.  \n우리가 쓰고 있는 컴퓨터에서 int * 은 long long과 크기가 같다.\n\n**Q**) 8bit / 16bit / 32bit / 64bit 컴퓨터의 의미??\n\u003e 한번에 처리 가능한 데이터의 크기, address line의 크기  \n한번의 hardware operation으로 처리할 수 있는 데이터의 길이  \n(대부분) 64bit 컴퓨터라면 데이터의 주소도 64bit length이다.  \n\n```c\n#include \u003cstdio.h\u003e\n\nint add(int a, int b)\n{\n    return a + b;\n}\n\nint main()\n{\n    int a = 100;\n    int b = 200;\n    int c;\n    // int * = long long \n\n    fprintf(stdout, \"%d : %lld %llx\\n\", a, \u0026a, \u0026a);\n    fprintf(stdout, \"%d : %lld %llx\\n\", b, \u0026b, \u0026b);\n    c = add(a, b);\n    fprintf(stdout, \"%d : %lld %llx\\n\", c, \u0026c, \u0026c);\n}\n```\n\n* 실행결과로 a, b, c의 주소가 4바이트씩 차이 나는 것을 볼 수 있다.  \n\n### `call by reference`  \n\n```c\n#include \u003cstdio.h\u003e\n\nint add(int *a, int *b)\n{\n    return *a + *b;\n}\n\nint main()\n{\n    int a = 100;\n    int b = 200;\n    int c;\n    // int * = long long \n\n    fprintf(stdout, \"%d : %lld %llx\\n\", a, \u0026a, \u0026a);\n    fprintf(stdout, \"%d : %lld %llx\\n\", b, \u0026b, \u0026b);\n    c = add(\u0026a, \u0026b);\n    fprintf(stdout, \"%d : %lld %llx\\n\", c, \u0026c, \u0026c);\n}\n```\n\n* call by reference도 실행결과 동일하게 잘 실행된다!  \n\n```c\n//a, b, c는 주소가 4바이트씩 차이난다.  \nint a = 100;\nint b = 200;\nint c = 999;\n```\n\n**Q**) 이때 `*(a + 4)`는 값이 b의 값인 200일까? [ **X** ]  \n\n**Q**) 이때 `*(a + 8)`는 값이 c의 값인 999일까? [ **X** ]  \n\n**Q**) 이때 `*(a + 1)`는 값이 b의 값인 200일까? [ **O** ]  \n\n**Q**) 이때 `*(a + 2)`는 값이 c의 값인 999일까? [ **O** ]  \n\n* a가 int 형이기 때문에 +1을 하게 되면 4바이트가 더해진다.  \n따라서 +1을 하면 4바이트 더해진 주소에 위치한 b값에 접근한다.  \n그리고 +2를 하면 8바이트 더해진 주소에 위치한 c값에 접근하게 된다.  \n\n```c\n#include \u003cstdio.h\u003e\n\nvoid add(int *a, int *b, int *c)\n{\n    *c = *a + *b;\n}\n\nint main()\n{\n    const int a = 100;\n    int b = 200;\n    const int c = 999;\n    // int * = long long \n\n    fprintf(stdout, \"%d : %lld %llx\\n\", a, \u0026a, \u0026a);\n    fprintf(stdout, \"%d : %lld %llx\\n\", b, \u0026b, \u0026b);\n    add(\u0026a, \u0026b, \u0026c);\n    fprintf(stdout, \"%d : %lld %llx\\n\", c, \u0026c, \u0026c);\n}\n```  \n\n* c가 const int 형임에도 불구하고 값에 바뀔 수 있다.  \n    * c의 포인터를 통해 값을 변경할 수 있다.  \n\n```c\n#include \u003cstdio.h\u003e\n\nvoid add(int *a, int *b, int *c)\n{\n    *c = *a + *b;\n}\n\nint main()\n{\n    const int a = 100;\n    int b = 200;\n    long long c = 999;\n    // int * = long long \n\n    fprintf(stdout, \"%d : %lld %llx\\n\", a, \u0026a, \u0026a);\n    fprintf(stdout, \"%d : %lld %llx\\n\", b, \u0026b, \u0026b);\n    add(\u0026a, \u0026b, \u0026c);\n    fprintf(stdout, \"%d : %lld %llx\\n\", c, \u0026c, \u0026c);\n    fprintf(stdout, \"%d : %lld %llx\\n\", c, (\u0026c)+1, \u0026c+1);\n    //fprintf(stdout, \"%d : %lld %llx\\n\", c, ((void *)(\u0026c))+1, \u0026c+1);\n    //원래는 long long 포인터인데 void 포인터로 바껴서 1씩 증가됨 (char 포인터도 1씩 증가)\n    fprintf(stdout, \"%d : %lld %llx\\n\", c, (\u0026c)+2, \u0026c+2);\n}\n```\n\n* 어떤 주소에 1을 더하는 것은 그 데이터 타입의 값(크기)를 더한다!  \n\n* (\u0026c) + 1 이나 (\u0026c) + 2 의 경우에도 주소가 어떤 데이터의 주소인지 물어보게 된다.  \n따라서 주소에 + 1 이나 주소에 + 2 되지 않는다.  \nc가 long long 형이므로 주소에 + 8바이트, 주소에 + 16바이트가 더해진 결과를 얻을 수 있다.  \n\n* 정말로 주소에 딱 1만 더하고 싶다면 ((void *)(\u0026c))+1 를 사용해야 한다.  \n    * 그럼 c가 long long의 포인터였다가 void 포인터로 바뀌게 되어 1씩 증가된다.  \n    * void와 char 포인터는 1씩 증가하기 때문이다.  \n\n* const는 automatic과 비슷하지만 다른 점은 이 값을 change하려 하면 컴파일러가 에러를 발생시킨다.  \n\n\u003cdiv style=\"text-align : center;\"\u003e\n    \u003cimg src=./img/three_model.png width=\"45%\" \u003e  \n\u003c/div\u003e  \n\n### `int an_array[] vs int *a_pointer`  \n\n* int an_array[32];\n    * Program will do;\n    * set aside a space on the stack big enough for 32 integers, \n    * declare that an_array is a pointer, and  \n    * bind that pointer to point to the newly allocated space  \n    * an_array라고 하는 포인터를 만든다!\n    * an_array는 배열의 시작 부분을 가리키고 있다.\n    * an_array 값이 저장되는 공간은 8바이트이다. 포인터이기 때문에.\n\n* int *a_pointer;\n    * Just pointer\n    * a_pointer = malloc(32*4);\n    * 포인터에게 어떤 값을 주기 전까지는 제대로 된 값을 갖고있는지 아닌지 알 수 없다.  \n\n### `array \u0026 pointer`  \n\n```c\n//sumarr.c\n#include \u003cstdio.h\u003e\n\nint sumArray3(int *a, int sum)\n{   \n    sum = *a;\n    a++;\n    sum += *a;\n    a++;\n    sum += *a;\n    fprintf(stdout, \"%d : %lld %llx\\n\", sum, \u0026sum, \u0026sum);\n    return a[3];\n}\nint main()\n{\n    int a = 100;\n    int b = 200;\n    int c = 999;\n    const int arr[4] = {100, 200, 300, 400};\n    int *parr;\n    parr = arr;\n    parr++;\n    fprintf(stdout, \"%d : %lld %lld\\n\", *parr, parr, arr);\n    c = sumArray3(arr, b);\n    fprintf(stdout, \"%d : %lld %llx\\n\", b, \u0026b, \u0026b);\n    fprintf(stdout, \"%d : %lld %llx\\n\", arr, arr, arr);\n    fprintf(stdout, \"%d : %lld %llx\\n\", *arr, *arr, *arr);\n    fprintf(stdout, \"%d : %lld %llx\\n\", \u0026arr, \u0026arr, \u0026arr);\n    fprintf(stdout, \"%d : %lld %llx\\n\", arr[2], \u0026arr[2], \u0026arr[2]);\n    fprintf(stdout, \"%d : %lld %llx\\n\", arr[3], \u0026arr[3], \u0026arr[3]);\n}\n```\n\n* arr = integer가 아닌 long long이다.  \n\n* *arr = a[0]이다.  \n\n* arr = \u0026arr = 배열의 시작 부분 주소이다.\n\n* arr[0], arr[1], arr[2], arr[3]은 4바이트씩 떨어져있다.\n\n* arr를 4개짜리로 선언했지만 arr[4]를 print해보면 arr[3]에서 4바이트 떨어진 주소가 출력된다.\n    * arr 길이가 4인데 5번째를 access 할 수 있다는 것이 이상하다.\n    * 에러가 나는 것이 정상인데 나지 않는다.\n\n* call by reference - 주소에 대한 데이터 변경하면 주소에 있는 값 변경된다.\n\n* call by value - value 값이 함수에서 아무리 바꾸려해도 바뀌지 않는다.  \n\n* Segmentation fault ( core dumped ) - memory protection\n    * a.out 를 실행할 때 주어진 공간을 벗어나서 접근했 때 발생한다.  \n    * segmentation violation\n    * core dumped - core라고 하는 파일에 프로그램의 snapshot이 만들어짐\n\n```c\nsum = a[0];         // a[0] = sum = 100\nsum += *(a+1);      // *(a+1) = a[1] = 200\nsum += *(a+2);      // *(a+2) = a[3] = 300\n\nsum = *a;           // *a = sum = 100\na++;                // a++ = a는 a[1]의 주소가 됨\nsum += *a;          // *a = sum = 200\na++;                // a++ = a는 a[2]의 주소가 됨\nsum += *a;          // *a = sum = 300\n```\n\n* *a + 1; 이나 *a + 2는 *a인 100에 1과 2를 더한 것이므로 101과 102이다.  \n    * value operater는 더하기보다 우선순위가 더 낮다.\n\n* 반면 *(a+1)는 a가 int형 포인터이므로 +1이 4바이트로 더해져 a[1]의 값인 200이 된다.  \n\n* 그리고 *(a+2)도 a가 int형 포인터이므로 +2이 8바이트로 더해져 a[2]의 값인 300이 된다.  \n\n* a 변수를 increment / decrement 할 수 있으므로 a의 저장공간이 있다는 것을 알 수 있다.\n\n```c\nint *parr;\nparr = arr;\nparr++;\n```\n\n* *parr = 200이 출력됨!\n\n* parr에 int 형 배열의 주소를 담고 있는 arr이 저장되었기 때문에 parr++ 하면 arr[1]의 위치를 가리키게 된다. 따라서 *parr은 200이다.\n\n***\n\n## Lecture 7\n##### - 2022. 01. 13  \n\n### `Noun-Adgective Form - 중요한 차이점!`  \n\n* `int const * A` : int가 상수 정수이며 이를 가리키는 포인터\n    * int 상수값은 변경될 수 없다. 대신 이를 가리키는 포인터는 변경될 수 있다.\n\n* `int * const A` : 이 포인터는 상수 포인터인데 변수는 int를 가리키고 있다.\n    * int 값은 변경될 수 있다! 주소는 변경 불가능\n\n### `함수의 포인터 연습`  \n\n```c\nvoid mul(int *a, int *b, int *c)\n{ *c = *a + *b;}\n\nint main()\n{\n    int const a = 100;\n    int b = 200;\n    int c = 9999;\n    int *p = \u0026a;\n    fprintf(stdout, \"a, b, c: %d %d %d\\n\", a, b, c);\n    *p = 200;\n    fprintf(stdout, \"a, b, c: %d %d %d\\n\", a, b, c);\n```\n\n* 만약 a에 다른 값을 그대로 넣으면 에러가 발생한다.\n    * assignment of read-only variable 'a'\n\n* 그런데 위 코드처럼 a의 주소를 p에 넣고, p가 가리키는 a의 주소에 들어있는 값을 변경하면 a의 값이 변하게 된다.  \n\n* const로 선언한 것이 주소를 통해서 값이 바뀐다면 어떤 의미가 있을까?\n    * error / warning이 나오게 하려는 의미가 있다! (위 코드에서 warning 발생 O)\n\n```c\nint * const p = \u0026a;         // case 1\np = \u0026b;\n\nint const * p = \u0026a;         // case 2\np = \u0026b;\n```\n\n1. 포인터가 const인데 b의 주소로 바뀌었으니 에러가 발생한다!  \n\n2. int 상수 값은 변하면 안되지만 이를 가리키는 포인터는 변해도 된다.\n    * 따라서 2번째 경우에는 에러가 발생하지 않는다!\n\n```c\nvoid *fp();         // 함수의 포인터\nfp = mul;           // 에러 발생\nfp(a, b, c)\n\nvoid (*fp)();\nfp = mul\nfp(\u0026a, \u0026b, \u0026c);\n```\n\n* fp가 가리키는 함수 mul은 parameter 3가지 모두 포인터로 받고 있기 때문에 fp를 호출할 때에도 a, b, c의 주소값을 넘겨줘야한다.  \n\n* mul 과 mul()의 차이점\n    * 선언문에 mul()은 함수를 선언한 것이다.  \n    * 실행문에 mul()은 함수를 실행하라는 것이다.  \n    * 따라서 실행문에는 mul을 사용해야한다.  \n\n### `void (*fp[4])(int *, int *, int *) = {add, sub, mul, div};`  \n\n* 포인터가 4개인 array이며, parameter는 int *, int *, int * 형을 받는다.\n\n* 그리고 그 포인터 4개는 add, sub, mul, div 함수를 각각 가리킨다.  \n\n```c\n//fnpointer.c\n#include \u003cstdio.h\u003e\n\nvoid add(int *a, int *b, int *c)\n{ *c = *a + *b;}\n\nvoid sub(int *a, int *b, int *c)\n{ *c = *a - *b;}\n\nvoid div(int *a, int *b, int *c)\n{ *c = (*a) / (*b);}\n\nvoid mul(int *a, int *b, int *c)\n{ *c = (*a) * (*b);}\n\n\nint main()\n{\n    int a = 100;\n    int b = 200;\n    int c = 0;\n    char ch;\n    int op = 0;\n    scanf(\"%d %c %d\", \u0026a, \u0026ch, \u0026b);\n\n    void (*fp[4])(int *, int *, int *) = {add, sub, mul, div};\n\n    switch(ch){\n        case '+':\n            op = 0;\n            break;\n        case '-':\n            op = 1;\n            break;\n        case '*':\n            op = 2;\n            break;\n        case '/':\n            op = 3;\n            break;\n    }\n\n    fprintf(stdout, \"a, b, c: %d %d %d\\n\", a, b, c);\n    fp[op](\u0026a, \u0026b, \u0026c);\n    fprintf(stdout, \"a, b, c: %d %d %d\\n\", a, b, c);\n    fprintf(stdout, \"fp %lld %lld %lld %lld\\n\", add, sub, mul, div);\n}\n```\n\n* 입력받은 숫자를 사칙연산하는 프로그램 (함수의 포인터 배열 이용)  \n\n* lld로 add, sub, mul, div를 출력하면?\n    * 함수의 주소가 출력된다.\n\n### `od`\na.out 코드 어떻게 생겼는지 보고싶다면 od 명령어를 사용한다.\n\n```bash\n$ od a.out\n$ od -x a.out       # 16진수로 보여줌\n```\n\n### `오늘의 목표`  \n\n* C compile process  \n* CPP - C Preprocessor\n* Compile options\n\n\u003cdiv style=\"text-align : center;\"\u003e\n    \u003cimg src=./img/compile.png width=\"60%\" \u003e  \n\u003c/div\u003e \n\n1. compile - compile 명령 넣음  \npreprocessor directive - C언어에서 #\n\n2. compile user source code - # 되어있던 것 모두 바뀜  \nAssembly 를 생성함\n\n3. Link Assembler - printf, scanf와 같은 함수들과 연결시켜줌 \u0026 실행파일 만들어줌  \n    1. static link - printf, scanf와 같은 것을 그냥 실행파일에 붙여줌\n        * 실행파일 사이즈 커짐, 대신 항상 어떤 기계에서든 실행됨\n    2. dynamic link - dynamic library에 있는 함수를 쓰게함\n        * 보안상의 이유 등으로 사용, 성능상으로 약간의 문제 있을 수 있다\n\n4. loader, loads the executable code into memory\n    * 주소는 실행될 때 결정된다. (실행될 때 메모리에 a.out가 load 된다)\n\n* Natural language\n* program language\n    1. 한줄 바꿔서 실행하기 반복 = interpreter\n        * ex - python\n    2. 프로그램 전체 번역해서 한번에 실행코드 생성 = compiler\n        * ex - C\n* Machine language\n\n### `gcc compile options`  \n\ngcc [-c|-S|-E] [-std=standard]\n [-g] [-pg] [-Olevel]\n [-Wwarn...] [-Wpedantic]\n [-Idir...] [-Ldir...]\n [-Dmacro[=defn]...] [-Umacro]\n [-foption...] [-mmachine-option...]\n [-o outfile] [@file] infile...\n\n* -c : generate .o file\n    * preprocessing \u0026 compile 까지만 실행\n* -g : for debug\n* -O : Optimization  \n    * 최적화, 의미가 없는 코드는 아예 지워버린다. (빨라짐!)\n* -E : generate preprocessing\n    * preprocessing만 실행 -\u003e .c 파일 만들어짐\n* -pg : for profile\n* -m32 -m64\n    * 32bit / 64bit 컴파일\n    * 64bit는 32bit에서 실행 불가\n    * 32bit는 64bit에서 실행 가능\n\n### `gcc option : preprocessor`  \n\n -Aquestion=answer -A-question[=answer] -C -CC -Dmacro[=defn] -dD -dI\n -dM -dN -dU -fdebug-cpp -fdirectives-only -fdollars-in-identifiers\n -fexec-charset=charset -fextended-identifiers -finput-charset=charset\n -fmacro-prefix-map=old=new -fno-canonical-system-headers -fpch-deps\n -fpch-preprocess -fpreprocessed -ftabstop=width -ftrack-macro-expansion\n -fwide-exec-charset=charset -fworking-directory -H -imacros file\n -include file -M -MD -MF -MG -MM -MMD -MP -MQ -MT\n -no-integrated-cpp -P -pthread -remap -traditional -traditional-cpp\n -trigraphs -Umacro -undef -Wp,option -Xpreprocessor option\n\n\u003e 잘 정리된 문서로 옵션 정리 해보기..!  \n\n### `gcc compile - for multiple file`\n\n```c\n//func.h\n#define DF(a) ((a) * (a))\nextern int func1(int x);\n\n//func.c\n#include \"func.h\"\nint func1(int a)\n{\n    return (a * 10);\n}\nint func2(int a)\n{\n    return (a * 2);\n}\n\n//main.c\n#include \u003cstdio.h\u003e\n#include \"func.h\"\n\nint main()\n{\n    fprintf(stdout, \"func %d %d\\n\", func1(100), DF(10));\n    //func 110 100\n}\n```  \n\n`gcc main.c func.c`  \n\n1. main.c 컴파일 -\u003e stdio.h preprocessing -\u003e func.h preprocessing  \n\n2. func.h의 DF(a) 대입해주고, func1에 대해 extern임을 마킹해둠  \n\n3. main.o 파일 생성  \n\n4. func.c 컴파일 -\u003e func.h 파일 가져옴, object file 만듦  \n\n5. 링킹 - printf \u0026 func1 에 대해 링크를 걸어둠.  \n\n    * printf - dynamic link  \n\n    * func1 - static link  \n\n**main.c에서 func2를 사용하고 싶다면 func.h에 반드시 extern 선언을 해주어야한다.**  \n\n* extern int func2(int x);\n\n`cc -c main.c` : main.c -\u003e main.o 생성해줌 (컴파일 : source code -\u003e object code)\n`cc -c func.c` : func.c -\u003e func.o 생성해줌 (컴파일 : source code -\u003e object code)\n`cc main.o func.o` : a.out 실행파일 만들어줌  \n\n이 상태에서 main.c를 수정했다면 `cc main.c func.o` 로 실행한다.  \n\nfunc.c를 수정했다면 `cc func.c main.o` 로 실행한다.  \n\n**Q**) 왜 이렇게 실행할까?\n\u003e 만약 func.c를 컴파일 할 때 많은 시간이 걸리고, func.c를 수정하지 않았다면 object code인 func.o를 그대로 사용한다.  \nmain.c를 수정했다면 main.c와 이전에 생성한 func.o를 컴파일해주면 된다.  \n\n### `C preprocessor (CPP)`  \n\n1. include head files  \n2. define macro  \n3. conditional compilation  \n4. line control  \n\n### `CPP - include file`\n\n* #include file as text  \n    * #include \u003cstdio.h\u003e or \"file.h\"  \n\n* gcc Option - I\n    * Include location - ./usr/include/\n    * default include location\n\n* prevent multiple include\n    * #pragma once\n    * #ifndef \\_MATH_\n    * #include \u003cmath.h\u003e\n    * #endif\n\n### `CPP - conditional compilation`  \n\n* #if\n* #ifdef\n* #ifndef\n* #elif\n* #else\n* #endif\n\n```c\n#ifdef _VERSION_\n#if _VERSION_ \u003e= 3\n    printf(\"Version is greater or equal than 3\\n\");\n#elif _VERSION_ == 2\n#error VERSION 2 IS NOT SUPPORTED\n#endif\n#endif  //ifdef _VERSION_\n```\n\n* 버전이 3보다 크면 print문을 출력한다.\n\n* 버전이 2와 같다면 에러가 발생한다.\n\n* ifdef의 짝은 마지막 endif로, \\_VERSION_ 이 정의되어있다면 조건을 만족하게 하고, 아니라면 점프한다.  \n\n### `Macro Definition`  \n\n* #define \u003cidentifier\u003e \u003creplcement tokenlist\u003e\n    * object\n* #define \u003cidentifier\u003e (\u003cparameter list\u003e) \u003creplacement token list\u003e\n    * function-like macro, note parameters\n\n* ex - #define f(a) ((a) * (a)) : 의도는 제곱!\n\n**위 예시에서 주의할 점! 무조건 parameter에 괄호치기**\n\n[ **good ex** ] #define f(a) ((a) * (a))\n\u003e f(20+13)으로 사용하면 ((20+13) * (20+13))이 되어 의도대로 작동한다. \n\n[ **bad ex** ] #define f(a) a*a\n\u003e f(20+13)으로 사용하고자 했다면 20 + 13 * 20 + 13이 되어 의도대로 작동하지 않는다.\n\n\u003cdiv style=\"text-align : center;\"\u003e\n    \u003cimg src=./img/func.png width=\"30%\" \u003e  \n\u003c/div\u003e  \n\n* cc -E func.c를 통해 func.h에 있던 extern 코드가 func.c로 온 것을 볼 수 있다.\n    * -E : preprocessing option\n\n* func.h에서 define한 DF(a)를 func.c에서 사용하면 DF(a) 대신에 ((a)*(a))가 들어가게 된다.\n\n* func.h의 메크로를 수정했다고 해보자.\n    * 수정한 이후에 기존에 생성한 object code를 cc main.o func.c 로 컴파일 했다면\n    * 수정한 내용이 반영되어 작동하지 않는다!\n\n**func.h처럼 수정된 메크로를 사용하는 모든 소스코드는 반드시 다시 컴파일해야한다.**\n\n따라서 모두 다시 컴파일해야하기 때문에 메크로를 자주 수정하는 것은 좋지 않다.  \n\n```c\n#define DF(a) ((-a) * (a))      //의도한대로 잘 동작하지 않는다.\nDF(a+1) == ((-a+1) * (a+1))     //이렇게 작동한다.\n\n#define DF(a) (-(a) * (a))\nDF(a+1) == (-(a+1) * (a+1)) \n```\n\n* 첫번째처럼 작성하면 10을 대입했을 때 -11 * 11이 나오지 않는다.\n    * 대신 -9 * 11이 계산된다.\n\n* 두번째처럼 작성하면 -11 * 11로, 의도대로 잘 작동한다.\n    * 따라서 괄호 적절하게 무조건 사용하기!\n\n**ex**) main.c와 func.h 두 파일에서 #include \u003cstdio.h\u003e 를 사용했다면?  \n\n* main.c에서 두번 include 된다. 그럼 오류가 날 가능성이 있다.\n\n* 따라서 func.h에 #pragma once 를 사용한다. 그럼 이 파일은 한번만 include 된다.\n\n```c\n#ifdef __FUNC_\n#define __FUNC_ 0\n//codes....\n#endif\n```\n\n* 또는 위 코드와 같이 func.h에서 __FUNC_가 정의되어 있다면 ifdef 아래 코드를 실행하고, 아니면 점프를 하게 할 수 있다.\n    * 그러면 `__FUNC_` 가 정의되지 않았을 때 한번만 실행하게 되고, 두번째 로딩할 때는 ifdef의 아래 코드가 실행되지 않는다.\n\n```c\n#ifndef __FUNC_\n\n#define __FUNC_ 0\n\n#if FUNCTION_NEGATIVE == 1\n#define DF(a) (-(a)*(a))\n#else\n#define DF(a) ((a) * (a))\n#endif\n\nextern int func1(int x);\nextern int func2(int x);\n\n#endif\n```\n\n1. __FUNC_가 정의되어있지 않다면 그 아래 코드 실행, 정의되어 있다면 점프한다.  \n\n2. FUNCTION_NEGATIVE가 1이라면 #define DF(a) (-(a)*(a)) 로 작동한다.  \n\n3. FUNCTION_NEGATIVE가 1이 아니라면 #define DF(a) ((a) * (a)) 로 작동한다.\n\n* #if 0 ~~~ #endif = 이 코드를 사용하지 않겠다! (command 처리하기 복잡할 때 사용하면 좋다.)\n\n***\n\n## Lecture 8\n##### - 2022. 01. 17  \n\n### `Macro 순서 예시`  \n\n```c\n// macrotest.c\n#define HE HI\n#define LLO _THERE\n#define HELLO \"HI THERE\"\n#define CAT(a, b) a##b\n#define XCAT(a, b) CAT(a, b)\n#define CALL(fn) fn(HE, LLO)\nCAT(HE, LLO)    // \"HI THERE\", because concatenation occurs before normal expansion\nXCAT(HE, LLO),  // HI_THERE, because the tokens originating from parameters (\"HE\" and \"LLO\") are expanded first\nCALL(CAT)       // \"HI THERE\", because parameters are expanded first\n```\n\n위 코드를 cc -E macrotest.c 로 preprocessing을 하면  \n\n* CAT(HE, LLO) -\u003e \"HI THERE\"  \n\n    * CAT(a, b)는 a##b이므로 concat 매크로를 통해 HELLO가 된다.  \n\n    * 그럼 HELLO가 매크로를 통해 \"HI THERE\"가 된다.  \n\n* XCAT(HE, LLO) -\u003e HI_THERE  \n    \n    * XCAT(HE, LLO)는 CAT(HE, LLO)이며 파라미터가 각각 먼저 expanded 되었기 때문에 CAT(HI, _THERE)가 된다. 따라서 concat 매크로를 통해 HI_THERE가 된다.\n\n* CALL(CAT) -\u003e \"HI THERE\" 의 결과를 얻게 된다.\n    \n    * CALL(CAT)은 CALL(HE, LLO)가 되고 concat 매크로를 통해 HELLO가 된다.  \n\n\n_되도록이면 이런식으로 macro 사용하지 않기..! 간단한 단어들을 매크로 사용하면 오히려 이해하기 어렵다._\n\n* 간단한 단어들을 #define의 identifier로 사용하지 않기.\n\n### `Special Macro and Directives`  \n\n```c\n__FILE__\n__LINE__\n```  \n\n* __FILE__에는 파일 이름이 프린팅 된다.\n    \n    * 여러 파일 컴파일 할 때 어떤 파일에서 오류가 났는지 모를 때 사용한다.  \n\n* __FILE__은 string, __LINE__은 integer이다.\n\n* #error 는 에러를 발생시키게 할 수 있다.\n\n### `Token stringification`  \n\n* string 토큰으로 바꿔준다.\n\n```c\n#define str(s)  #s\nstr(p = \"foo\\n\";)       //outputs \"p = \\\"foo\\\\n\";\"\nstr(\\n)                 //outputs \"\\n\"\n```\n\n* #s로 매크로를 정의하면 문자열로 만들어준다.\n\n* print 매크로를 만들고 싶은데 어떤때에는 %d, %c, %s로 프린트 하고 싶을 때 token stringification을 사용하면 유용하다.  \n\n### `Token Concatenation`  \n\n* 두개를 붙여주는 매크로이다.\n\n```c\n#define DECLARE_STRUCT_TYPE(name) typedef struct name##_s name##_t\nDECLARE_STRUCT_TYPE(g_object);\n//outputs: typedef struct g_object_s g_object_t\n```\n\ng_object가 매크로의 name이 위치한 곳에 들어가 붙여져서 결과가 typedef struct g_object_s g_object_t 가 된다.  \n\n* 왜 #define sq(a) a*a를 사용할 때 concatenation 해야하는가?  \n\n```c\n#define sq(a) a*a\nsq(B)\n#define sq(a) aaa\nsq(C)\n#define sq(a) a##a##a\nsq(D)\n```\n\n* sq(B)는 B*B가 되는 것은 맞다.  \n\n* sq(C)가 출력할 때는 CCC가 나오는 것이 아니라 그냥 aaa의 결과를 얻게 된다.  \n\n* 따라서 붙여쓰고 싶다면 마지막처럼 a##a##a로 concatenation을 정의해야 DDD 라는 결과를 얻을 수 있다.\n\n### `GCC Optimization`  \n\n* 최적화에 대한 table 존재  \n\n|Option|Meaning|\n|:--------:|:--------:|\n|-O0(기본값)|최적화를 수행하지 않는다.|\n|-O / -O1|코드 크기와 실행 시간을 줄이는 것을 제외한 최적화는 실행하지 않는다. |\n|-O2|메모리 공간과 속도를 희생하지 않는 범위내의 모든 최적화를 수행한다. loop unrolling과 function inlining에 대한 최적화를 수행하지 않는다.|\n|-O3 / -O2|최적화에 인라인 함수와 레지스터에 대한 최적화를 추가로 수행한다.|\n|-Os / -O2|최적화 기능을 사용하지만, 코드 크기를 증가시키는 최적화는 생략한다.|\n\n* optimization을 하다보면 코드 크기가 커진다.  \n\n### `함수의 메모리 공간`  \n\n```c\nint fun(int a){\n    \n    int b;\n    return a * a;\n}\n\nint main(){\n    int a = 100;\n    fun(a);\n}\n```\n\n* 실행하기 전에 필요한 데이터 넣어둔다.  \n    * main의 메모리 공간에 a의 4바이트 등\n\n* 함수가 호출되면 호출될 때 메모리 stack 만든다.  \n    * parameter a를 받기 위한 메모리\n    * int b를 위한 메모리\n    * return 값 저장하기 위한 메모리  \n\n* main에 있는 a와 함수에 있는 a는 다르다! 다른 위치의 메모리에 위치한다.  \n\n* optimize하면 사용하지 않는 변수인 int b를 사용하지 않는다. (사라진다.)  \n\n* *fn에서 `return a * a`하는 것과, main에서 `b = a *a` 하는 것의 차이는?\n\n**Q**) 함수를 만드는 것이 좋을까? 만들지 않는 것이 좋을까?  \n1. 성능은 어느쪽이 빠를까 (main 코드 vs 함수)  \n2. 코드 길이는 어떻게 구현하는 것이 짧을까\n\n**Q**) 함수는 stack 만드는 비용이 들어서 main 코드가 성능이 빠를 것 같은데 왜 함수를 사용하는가?\n\u003e main함수나 다른 함수들에서 그 함수가 1000번 소스코드에 appear 된다고 가정하면, 코드의 길이 입장에서는 main에  당연히 함수로 만드는 것이 좋다.  \n\n* **#define으로 함수 정의하는 것은 잘 사용하기만 한다면 성능면에서와 코드 길이면에서 좋다!**\n\n* #define으로 함수 정의하면 함수의 내용이 그대로 들어가게 된다.  \n\n* c++에서는 inline으로 코드 끼워넣을 수 있다. (함수의 코드 자체가 그대로 들어간다.)\n\n### `C Compile and Execution`  \n\n* [ C Compile and Execution ](#오늘의-목표)\n    * compile 과정 복습\n\n### `gcc -options`  \n\n* 옵션이 매우 많은데 중요한 것만 뽑은 내용이다.\n\n* -std=\u003cstandard\u003e Assume that the input sources are for \u003cstandard\u003e.\n* -E Preprocess only; do not compile, assemble or link.\n    * CPP, c preprocessor만 실행함\n* -S Compile only; do not assemble or link.\n    * compile만 함\n* -c Compile and assemble, but do not link.\n    * .o 파일을 만든다.\n* -o \u003cfile\u003e Place the output into \u003cfile\u003e.\n\n### `gcc machine option (x86 \u0026 x86 win)`  \n\n* 컴파일된 실행파일 a.out가 다른 기계에서도 실행되면 좋을 것 같을 때 machine option을 사용한다.  \n\n* arm에서 사용하도록 하고 싶다면 arm용 컴파일러를 설치하여야 한다.  \n\n* -m32 -m64 -mx32 -m16 \n    * 각각 32bit, 64bit\n\n### `gcc option: preprocessor`  \n\n* -Aquestion=answer\n * preprocessor가 질문하는 경우가 있다. answer에 yes라 해두면 계속 yes로 대답함\n\n* -dI: include 파일은 이 디렉토리에서 가져오도록 설정\n\n### `Must Know..`  \n\n* 여기에 있는 내용은 꼭 알고 있기\n\ngcc [-c|-S|-E] [-std=standard]\n [-g] [-pg] [-Olevel]\n [-Wwarn...] [-Wpedantic]\n [-Idir...] [-Ldir...]\n [-Dmacro[=defn]...] [-Umacro]\n [-foption...] [-mmachine-option...]\n [-o outfile] [@file] infile...\n\n* -c : generate .o file\n    * preprocessing \u0026 compile 까지만 실행\n* -g : for debug\n* -O : Optimization  \n    * 최적화, 의미가 없는 코드는 아예 지워버린다. (빨라짐)\n* -E : generate preprocessing\n    * preprocessing만 실행 -\u003e .c 파일 만들어짐\n* -pg : for profile\n* -m32 -m64\n    * 32bit / 64bit 컴파일\n    * 64bit는 32bit에서 실행 불가\n    * 32bit는 64bit에서 실행 가능\n\n### `compile 순서와 옵션`  \n\n1. cc -E hello.c \u003e hellocpp.c = c preprocessing, cpp 코드 만들어줌\n2. cc -S hellocpp.c = hellocpp.s 만들어짐, compile해서 assembly로 고쳐짐\n3. cc -c hellocpp.s = hellocpp.o 만들어짐, object 코드 만들어짐\n4. cc -o hellocpp hellocpp.o = 실행파일 hellocpp.out가 만들어진다!  \n\n### `CPP processing`  \n\n* Character set\n    * utf-8 = 유니코드\n\n* Initial processing\n    1. LF, CR LF and CR processing\n        * 줄바꿈 코드를 모드 CR로 바꾼다.  \n\n    2. if –trigraphs\n\n    3. long line with “\\” -\u003e merge\n        * 긴줄, 여러줄 줄 바꿔서 쓰고 싶을 때 사용한다.\n        * \\을 사용하면 대신 c preprocessing 이 한줄로 다시 붙인다.\n\n    4. All comments -\u003e “ ”\n        * 모든 comment는 \" \"로 지운다.\n\n* Tokenization with space\n    * #define foo() bar\n    * foo()bar -\u003e bar bar    not    barbar    // use ## for concat\n    * foo()bar를 했을 때는 barbar가 아닌 bar bar의 결과를 얻을 수 있다.\n    * barbar처럼 붙어있는 결과를 얻고 싶다면 ## concatenation을 사용한다.\n\n* Preprocessing language\n    * inclusion of header / Macro Expansion / Conditional Compile / Line Control Diagnostics (에러 발생)\n\n* od -x -c hello.c\n\n\u003cdiv style=\"text-align : center;\"\u003e\n    \u003cimg src=./img/od.png width=\"70%\"/\u003e  \n\u003c/div\u003e\n\n* 여기서 \\n이 들어가있고 \\n이 0a = 10임을 알 수 있다.  \n\n* pc에서는 \\n과 \\r이 들어가있는데 유닉스에서는 \\n만 들어있다.  \n\n    * 줄바꿈을 표현하는 방법은 시스템과 운영 체제에 따라 여러 가지가 있다. \n    * 윈도우는 ASCII의 CR+LF로 새줄을 나타내고 유닉스는 LF로 새줄을 나타낸다. \n    * 맥 OS은 새줄 문자로 버전 9까지 CR을 썼지만 버전 10부터 LF를 쓰고 있다.\n    \n* 위에서 언급한 CR processing이 일어나면 \\n으로 다 바뀐다.\n\n* MS word 왼쪽, 오른쪽 구분되는 따옴표는 유니코드이다. -\u003e C 언어에서 사용 불가!\n    * printf(“Hello World\\n”\");  \n\n### `Macro Definition (1)`  \n\n* #define PI 3.14159 = 텍스를 대치줌\n\n* 괄호로 묶어주는 것이 안전하다.\n\n### `Macro Definition (2)`  \n\n* Multiple lines\n```c\n#define NUMBERS 1, \\\n                2, \\\n                3  \n\nint x[] = { NUMBERS };  //int x[] = { 1, 2, 3 };  \n//define 활용한 예시\n```\n\n여러줄로 define 하고 싶을 때 위에서 나온 back slash (\\)을 사용한다.  \n\n* Define Where?\n\n```c\n    foo = X; \n    #define X 4 \n    bar = X;    // foo = X and bar = 4\n```\n\ndefine은 어디에서나 할 수 있는데, 자신 직전에 했던 define이 작동한다.\n\n```c\n#define TABLESIZE BUFSIZE\n#define BUFSIZE 1024 // TABLESIZE -\u003e BUFSIZE  -\u003e 1024 [X]\n```\n\nTABLESIZE 가 BUFSIZE임을 정의하기 전에 BUFSIZE가 1024로 정의되어 있지 않아서 TABLESIZE가 1024로 작동하지 않는다.  \n\n```c\n#define BUFSIZE 1020\n#define TABLESIZE BUFSIZE\n#undef BUFSIZE\n#define BUFSIZE 37   // TABLESIZE = 37\n```\n\n이 경우에서는 BUFSIZE를 정의하고 그 다음에 TABLESIZE를 정의하였기 때문에 잘 작동한다.  \n\n### `Macro Definition (3) - Function like Macro`  \n\n* C언어에서 if 조건문은 성능을 떨어뜨리는데 C 언어에서 사용하는 ? 조건문은 생각보다 성능이 좋다.  \n\n```c\n#define min(X, Y) ((X) \u003c (Y) ? (X) : (Y))\n```\n\n조건이 true이면 X이고, false이면 Y가 된다.  \n\n* omit parameter  \n\n```c\nmin(, b) -\u003e (()\u003c(b) ? ( ) : (b))\n```\n\n빈 parameter에 무엇이 들어가든 모든 빈 공간에 paramter가 들어간다.  \n\n따라서 빈 paramter에 값이 들어가면 조건에 따라 새로 들어간 parameter 혹은 b 를 얻게 된다.  \n\n**대신 paramter 개수는 맞춰서 넣어줘야 한다.**\n\u003e 위 경우에는 paramter 2개 필요! parameter 개수 맞지 않으면 에러 발생  \n\n### `Macro Definition (4) - Stringization and concat`  \n\n* Stringization\n    * Parameter leading with #\n    * 위에서 본 예시 참고 -\u003e paramter 안의 모든 것 string으로 바꿔줌\n\n* Concatenation\n    * ##을 사용하면 paramter로 들어온 것을 공백없이 합쳐주거나 공백없이 그 자리에 넣어준다.\n\n### `Macro Definition (5) - Variadic`  \n\n```c\neprintf (\"%s:%d: \", input_file, lineno) \nfprintf (stderr, \"%s:%d: \", input_file, lineno)  \n\n#define eprintf(format, ...) fprintf (stderr, format __VA_OPT__(,) __VA_ARGS__)\n```\n\n* 뒤에 parameter들이 개수에 따라 여러개의 parameter 개수가 될 수 있는 함수 만들 수 있다.\n\n### `Macro 예시`  \n\n* Misnesting  \n\n```c\n#define twice(x) (2*(x))  \n#define call_with_1(x) x(1)  \ncall_with_1 (twice)  // -\u003e twice(1)  -\u003e (2*(1))  \n\n#define strange(file) fprintf (file, \"%s %d\", strange(stderr) p, 35); // -\u003e fprintf (stderr, \"%s %d\", p, 35);  \n```\n\n* 위 예시처럼 코드 짜지 않기..  실행이 되긴 되긴 하지만 이해하기 어렵다.\n\n* Operator precedence  \n\n* Newline\n\n### `Predefined Macros`  \n\n* All Standards\n\n```c\n__FILE__    // Filename with full path string\n__LINE__    // Decimal number of current line\n```\n\n* __LINE__으로 line number를 바꿀 수 있다.\n\n```c\n//hello.c\n#include \u003cstdio.h\u003e\n\nvoid add(int *a, int *b, int *c)\n{\n        *c = *a + *b;\n}\n\nint main()\n{\n        int a = 100;\n        int b = 200;\n        int c = 999;\n        // int * = long long\n\n        fprintf(stdout, \"%d : %lld %llx\\n\", a, (long long )\u0026a, (long long)\u0026a);\n        fprintf(stdout, \"%d : %lld %llx\\n\", b, (long long)\u0026b, (long long)\u0026b);\n        add(\u0026a, \u0026b, \u0026c);\n        fprintf(stdout, \"%s %d : %d \\n\", __FILE__, __LINE__, c);\n}\n```\n\n```bash\n$ a.out\n100 : 140734210326444 7fff3c9d3fac\n200 : 140734210326448 7fff3c9d3fb0\nhello.c 18 : 300\n```\n\n* 위 hello.c 코드에서 사용한 __FILE__과 __LINE_으로 파일 이름 hello.c와 line number 18이 출력된 것을 볼 수 있다.\n\n* 만약 print문 직전에 `#define __LINE__ 1000` 매크로를 사용했다면 print문의 line number가 1000으로 출력된다.\n\n* `#error 1024`를 사용하면 컴파일 시도할 때 바로 에러가 발생한다.\n\n```c\n#define ERR_DATA 1000\n#if ERR_DATA \u003e 1000\n#error 1024\n#else\n#warning ERR_DATA\n#endif\n        fprintf(stdout, \"%s %d : %d \\n\", __FILE__, __LINE__, c);\n```\n\n* 위 코드는 ERR_DATA가 1000이므로 에러가 나지 않고 warning과 함께 아래의 print문이 출력된다.\n\n* line number를 define하면 line number가 증가하지 않는다. -\u003e 되도록이면 line number 지정하지 않기.\n\n### `Project`  \n\n* 아주대학교의 임베디드 시스템을 위한 고정소수점 수학 라이브러리 개발  \n\n* 고정소수점 \u003c-\u003e 부동소수점 (뜰 부, floating point)\n\n* 10010101 = 정수로 149 (10진수)\n\n* 2진수 1101.11 = 9.75\n    * 소수점 뒤 부분은 1/2, 1/4가 된다.  \n\n* 부동소수점  \n\n\u003cdiv style=\"text-align : center;\"\u003e\n    \u003cimg src=./img/floating_point.png width=\"70%\"/\u003e  \n\u003c/div\u003e\n\n* 위 사진에서 1 / 10000101 / 11011010100000000000000 를 10진수로 바꾸고 싶다면\n    * 순서대로 각각 s, e, m\n    * 1.m * (2 ^ (e-127)) 이다.\n    * 부호는 (-2S + 1) 로 이를 곱해줘야한다.\n\n* 만약 32bit signed 정수를 2의 보수로 표현한다면\n    * s / 15bit / 16bit\n    * signed int a 의 실제 값은 a * 2 ^ (-16) 이다.\n\n### `입력받은 수를 fixed point로 출력하는 프로그램`  \n\n```c\n//pcc001_final / test.c\n#include \u003cstdio.h\u003e\n\n// #### #### #### #### .  #### #### #### ####\n// S 15 . 16\n\n#define FX_Q_NUM 16\n#define FX_2_MINUS_16 1.52587890625e-05\n#define FX_2_PLUS_16 65536\n\nint main()\n{\n    int ia;\n    float fa;\n    fscanf(stdin, \"%d\", \u0026ia);\n    fprintf(stdout, \"%d : %d %d\\n\", 2, 16, 2^16 );\n    fprintf(stdout, \"%d : %f %f\\n\", ia, (float)ia, (float)ia *  FX_2_MINUS_16);\n    //ia를 fixed point로 출력하고 싶다면 float형으로 바꾸고 2의 -16승을 곱해준다.\n    fscanf(stdin, \"%f\", \u0026fa);\n    fprintf(stdout, \"%f : %d %d\\n\", fa, (int)fa, (int) (fa * FX_2_PLUS_16));\n    //floating point에 2의 16승을 곱하고 int형으로 바꿔 fixed point로 출력한다.\n}\n```\n\n* fixed point로 바꾸기\n    * int형 데이터 -\u003e float 형으로 바꾸고 2의 -16승을 곱해준다.\n    * float형 데이터 -\u003e 2의 16승을 곱하고 int형으로 바꿔준다.\n\n***\n\n## Lecture 9\n##### - 2022. 01. 18  \n\n### `project`  \n\n* 아주대학교의 임베디드 시스템을 위한 고정소수점 수학 라이브러리 개발  \n\n* CPU가 하는 중요한 작업 두가지\n    * ALU - arithmetic logic unit\n    * CU - control unit\n\n* +, -, *, /, \u0026, |, ^, ~, \u003e\u003e, \u003c\u003c : 보통 단위 사이클에 끝남\n    * 곱셈, 나눗셈 : 어떤 컴퓨터에서는 한 사이클에 끝나지만 어떤 컴퓨터에서는 아닐 수도 있다.\n\n* ex) Processor : Intel(R) Core(TM) i7-8700K CPU 3.70GHz\n    * 기본 한 사이클 : 1 / clock speed = 1 / 3.7GHz = 0.27 nano second\n\n* fixed point를 사용하는 이유?\n    * floating point 연산은 integer 연산에 비해 매우 비싼 연산이다.\n    * 내가 표현하고 싶은 수가 정수가 아니라 유효숫자가 있는 수를 표현하고 싶다면 int로 표현하되 소숫점을 고정해서 표현한다.\n\n* #define FX_S32_31은 signed 32bit + 31bit이니까 64bit long long을 사용해야한다.\n\n* #define FX_S47_16 -\u003e signed long long\n\n* #define FX_S16_15 \u0026 #define FX_S23_08 -\u003e signed integer\n\n* #define FX_S8_7 -\u003e signed short\n\n* #define FX_S4_3 -\u003e signed char\n\n### `S 15 . 16`  \n\n```c\n#include \u003cstdio.h\u003e\n\n// #### #### #### #### .  #### #### #### ####\n// S 15 . 16\n\n#define FX_Q_NUM 16\n#define FX_2_MINUS_16 1.52587890625e-05F\n#define FX_2_PLUS_16 65536\n#define FX_S_15_16 11516\n#define FX_SYSTEM FX_S_15_16\n\ntypedef int fixed32;\n\nfixed32 fromFloat(float fa)\n{\n    return (fixed32) (fa * FX_2_PLUS_16);\n\n}\n\nfloat toFloat(fixed32 xa)\n{\n    return ((float)(xa)) * FX_2_MINUS_16;\n\n}\n\nfixed32 fxAdd(fixed32 a, fixed32 b)\n{\n    return fromFloat((toFloat(a) + toFloat(b)));\n}\n\nfixed32 fxAdd2(fixed32 a, fixed32 b)\n{\n    return a + b;\n}\n\nint main()\n{\n    long long i=0;\n    int ia, ib, ic, ic2;\n    float fa;\n    //fscanf(stdin, \"%d %d\", \u0026ia, \u0026ib);\n    for(i = 0; i \u003c (long long )256 * 256 * 256 * 256 ; i += (256 * 256))\n    {\n        ic = fxAdd(i, i);\n        ic2 = fxAdd2(i, i);\n        fprintf(stdout, \"%f + %f : %f, %f diff = %d\\n\", toFloat(i), toFloat(i), toFloat(ic), toFloat(ic2),ic-ic2 );\n    }\n    //fprintf(stdout, \"%d + %d : %d\\n\", ia, ib, ic);\n    //fprintf(stdout, \"%f + %f : %f\\n\", toFloat(ia), toFloat(ib), toFloat(ic));\n}\n```\n\n* #define FX_2_PLUS_16의 65536을 (1\u003c\u003c16)으로 사용해도 성능상에서는 차이 없다.\n\n* fromFloat 함수 : fixed point로 변환해서 return\n\n* toFloat 함수 : floating point로 변환해서 return\n\n* fxAdd : fixed point를 floating point로 변환 후에 더하고 다시 fixed point로 변환해서 return 해줌\n\n* fxAdd2 : 그냥 a와 b를 더해서 return  \n\n**Q**) fxAdd와 fxAdd2의 결과는 같을까?\n\u003e ic에는 fxAdd의 결과를, ic2에는 fxAdd2의 결과를 저장하였다.  \n실행결과는 result.out에 저장함.  \n\n`project - 보고서에 써야할 점`  \n\n* i가 0에서부터 500만까지 i++ 해서 들어갈 때, 결과를 출력해보면 0.000000 + 0.000000....이고 그 다음이 0.000015 였다.  \n\n* 이 숫자가 표현할 수 있는 가장 작은 숫자의 차이가 0.000015라는 뜻이다.\n\n\u003e 이 시스템은 정수파트가 15비트, 소수점 이하 부분이 16비트인 시스템인데 이 시스템에서 표현할 수 있는 가장 작은 차이의 수는 0.000015 입니다.  \n정확한 값인지 아닌지는 나중에 계산해봐야함 -\u003e 0.000015가 맞았다면 그 다음이 0.000030이어야 하는데 0.000031이니까 계산해봐야함  \n\n* i = long long, for (i = 0 ; (long long) 256 * 256 * 256 * 256; i += (256 * 256) ) 실행 했을 때 결과 중 오버플로우 발생\n    * 이때 16385.000000 + 16385.000000 = -32768.000000 으로 오버플로우 발생\n\n### `debugging`  \n\n* gcc compile options 중에 -g 가 for debug\n\n* pcc001_final/test.c를 수정해서 일부러 \u0026ib를 ib로 scanf 하여 에러가 발생하도록 하였다.\n\n```bash\n$ cc -g test.c\ntest.c: In function ‘main’:\ntest.c:41:21: warning: format ‘%d’ expects argument of type ‘int *’, but argument 4 has type ‘int’ [-Wformat=]\n  fscanf(stdin, \"%d %d\", \u0026ia, ib);\n\n$ ./a.out\n200 200         # 200 200 입력함\nSegmentation fault (core dumped)\n\n$ file a.out\na.out: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=a4867b47f1cd5e4faf38b42c8bde146a4cfc100d, with debug_info, not stripped\n\n# a.out 파일에 디버깅 내용 들어가서 크기가 확 커짐\n\n$ gdb a.out\n```\n\n* gdb 사용하는 방법 = gdb 실행파일 = gdb a.out\n\n### `gdb - GNU debugger`  \n\n* gcc -g 옵션으로 컴파일하고 gdb를 통해 디버깅\n\n```bash\n(gdb) run           # 실행\nStarting program: /home/course/pcc001/pcc/lec09/a.out\n500 500             # scanf로 입력받을 값 넣어줌\n\nProgram received signal SIGSEGV, Segmentation fault.\n0x00007ffff7a53932 in _IO_vfscanf_internal (s=s@entry=0x7ffff7dcfa00 \u003c_IO_2_1_stdin_\u003e, format=\u003coptimized out\u003e,\n    argptr=argptr@entry=0x7fffffffe0f0, errp=errp@entry=0x0) at vfscanf.c:1898\n1898\tvfscanf.c: No such file or directory.\n# 에러가 scanf에서 발생했음을 알 수 있다.\n\n(gdb) where         # 에러가 발생한 현재 위치가 어디인지 알려줌\n#0  0x00007ffff7a53932 in _IO_vfscanf_internal (s=s@entry=0x7ffff7dcfa00 \u003c_IO_2_1_stdin_\u003e, format=\u003coptimized out\u003e,\n    argptr=argptr@entry=0x7fffffffe0f0, errp=errp@entry=0x0) at vfscanf.c:1898\n#1  0x00007ffff7a60356 in __isoc99_fscanf (stream=0x7ffff7dcfa00 \u003c_IO_2_1_stdin_\u003e, format=\u003coptimized out\u003e)\n    at isoc99_fscanf.c:34\n#2  0x000055555555485d in main () at test.c:41\n\n(gdb) pwd\nWorking directory /home/course/pcc001/pcc/lec09.\n\n(gdb) list\n1893    in vfscanf.c\n\n(gdb) list main\n32  {\n33      return a + b;\n34  }\n35\n36  int main()\n37  {\n38      long long i=0;\n39      int ia, ib, ic, ic2;\n40      float fa;\n41      fscanf(stdin, \"%d %d\", \u0026ia, ib);\n```  \n\n* gdb 명령어  \n    * run : 실행\n    * where : 에러가 발생한 현재 위치가 어디인지 알려줌\n    * pwd : 현재 작업 디렉토리\n    * list : 현재 vfscanf.c를 보고있다.\n    * list function_name : 함수의 소스코드를 보여준다.\n\n* where를 통해 알게 된 점  \ntest.c의 41번째 라인에서 에러가 발생했다.  \ntest.c의 main() 함수에서 __isoc99_fscanf를 호출하였고, 이 함수는 _IO_vfscanf_internal 함수를 호출하였다.  \n== `call stack`  \n\n```bash\n(gdb) list\n29      return a + b;\n30  }\n31\n32  int main()\n33  {\n34      long long i=0;\n35      int ia, ib, ic, ic2;\n36      float fa;\n37      fscanf(stdin, \"%d %d\", \u0026ia, ib);\n\n(gdb) break 34\nBreakpoint 1 at 0x833: file test.c, line 34\n\n(gdb) run\nStarting program: /home/course/pcc001/lec09/a.out\n\nBreakpoint 1, main() at test.c:34\n34              int i=0;\n\n(gdb) print i\n$i =0\n\n(gdb) step\n37              fscanf(stdin, \"%d %d\", \u0026ia, ib);\n# 왜 다음 줄인 35번이 아니라 37번을 실행한 것일까?\n# 실행문이 아니라 선언문이므로 다음 실행문이 37번 라인을 실행함\n\n(gdb) print ia\n$2 = 32767\n(gdb) print ic\n$3 = 0\n(gdb) print ic2\n$4 = 21845              # 변수에 garbage 들어가있는 모습\n\n(gdb) watch ic\nHardware watchpoint 2: ic\n\n(gdb) continue\nContinuing.\n0.000000 + 0.000000 : 0.000000 , 0.000000 diff = 0\n\nHardware watchpoint 2:ic\n\nOld value = 0\nNew value = 131072\nmain () at test.c:41\n41                      ic2 = fxAdd2(i, i);\n# ic 값이 40 라인에서 바뀌어서 바로 그 다음줄 41번 라인에서 stop한다.\n```\n\n* gdb 명령어\n    * break line_number : line number로 breakpoint 지정해줌\n        * break 함수명도 가능\n    * run : breakpoint 지정했다면 실행 후 그 라인에서 멈춤\n    * print 변수 : 현재 변수에 저장된 값 볼 수 있음\n    * step : 그 다음 줄 실행 (실행문) - 호출된 함수의 소스코드로 들어갈 수 O\n    * next == ni : 현재 소스코드의 다음 줄 실행\n    * continue : 계속 실행하고 싶을 때\n    * quit : 실행 process 종료\n    * clear breakpoints line_number : line number로 지정된 breakpoint 삭제\n    * bt :  충돌이 일어난 시점에서 프로그램의 현재 호출 스택 보여줌 (call stack)\n        * ex) fromFloat를 fxAdd가 호출하였고, fxAdd를 main이 호출하였음을 알 수 있다.  \n    * watch 변수명 : 어떤 변수의 값이 변했을 때 stop 시키고 싶다면 사용\n\n**next vs step**  \nnext : 현재 소스코드의 다음 줄 실행  \nstep : 다음 줄 실행하긴 하는데 호출된 함수의 소스코","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkwaksj329%2Fpracticalcoding","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkwaksj329%2Fpracticalcoding","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkwaksj329%2Fpracticalcoding/lists"}