모두코드 C언어 #1
원본 링크 - 씹어먹는 C언어 시작하기
Table of Contents
공부 수칙
- 강좌를 다 읽었다면 머리속으로 정리한다. (나는 블로그로 정리할 것)
- 위 과정이 잘 안된다면, 다시 한 번 읽는다. 잘 모르겠으면, 질문을 남긴다
- 강좌에 나오는 모든 소스 코드를
직접 타이핑
해서 쓴다. - 강좌를 따라 만들며, 자기 마음대로 수정해서 원하는 형태로 바꿔본다.
- 본인이 만든 프로그램을 자부심을 가지고 인터넷에 올려본다.
Before C Language…
- 보통 첫 언어는
Python
이겠지만… 가끔불쌍한 영혼
은C
로 시작한다… (나도 그랬다) C
언어의 특성 상, 컴퓨터에 대한 배경 지식이 없으면, 이해하기 매우 어렵다. (그래서 성적이 별로였다…)C
언어는 1972년에 출시된 언어이므로, 확실히 올드한 느낌이 있다.- 탄생 목적은
Unix
운영체제를 작성하기 위해서, 즉 시스템 프로그래밍이 주 목적 (컴퓨터 시스템과 밀접) - 중요한 특징으로, 배울 내용이 적다는 장점이 있다! (다른 프로그래밍 언어에 비해서, 배우기 쉽다곤 안했다)
컴퓨터는 뭘까?
-
컴퓨터는 말 그대로 계산기
-
어떤 연산을 빠르게 처리해주는 역할을 수행
-
컴퓨터는
명령어를 읽어서
주어진 명령어에 따라연산을 수행
-
누가? 어디서? 명령어를 읽으며, 프로그램은 무엇이며, 명령어는 어떻게 작성하는지?
- 컴퓨터의 연산은
CPU
(Central Processing Unit)이 처리합니다. - 대략 1초에 10억번 개의 연산을 처리하며, 발열이 심하므로, 보통 쿨러 아래에 설치됩니다.
- 최근에는 그래픽 관련 연산을 처리하는
GPU
가 있지만, 범용적인 명령어들은CPU
에서 처리됩니다. CPU
가 명령어를 실행하려면, 명령어를 읽어야하며, 연산된 결과를 저장해야합니다.CPU
가 연산을 수행하기 위해 데이터를 저장하는 곳을Register
라고 합니다.- 일반적인 연산을 수행할 수 있는
Register
는 16개뿐입니다. (64bit CPU 기준) - 또한 각
Register
는 64bit의 데이터를 담을 수 있으므로, 총 128 Byte만 저장이 가능합니다. - 장점이라면
Register
는 아주 빠르게 접근할 수 있습니다. - 더 많은 공간이 필요할 때는
RAM
을 이용합니다. (Random Access Memory) RAM
에 명령어들을 저장해놓고 있다가, 연산을 수행할 때,RAM
에서 읽어옵니다.RAM
의 문제라면, 휘발성 메모리이므로, 전원을 껐다가 키면 사라집니다.- 늘 새롭게 모든 것을 실행할 수는 없으므로, 비휘발성 메모리가 필요한데 이와 같은 것이
HDD
orSSD
가 되겠습니다. - 전체적인 흐름을 본다면,
CPU
가RAM
에 명령어를 저장해두었다가, 꺼내며 연산을 수행하며, 연산 결과에 해당하는 정보를HDD
orSSD
에 결과로 저장하는 형태입니다. RAM
이HDD
나SSD
보다는 빠르지만, 생각보다 그렇게 빠르지 않기 때문에, 직접적인 연산을 수행하지는 않지만, 빠르게 데이터를 불러올 수 있는Cache
라는 공간을 사용합니다.Register
는 직접적으로 연산을 수행하기 위한 데이터를 저장하는 공간이며,Cache
는 직접적으로 연산을 수행하지는 않지만, 빠른 접근을 위해 사용하는 공간입니다.Cache
는 L1, L2, L3로 이루어지며, L1이 가장 빠르고 가장 작으며, L3가 가장 느리지만 가장 큽니다.CPU
는 조만간 사용할 데이터를Cache
에 불러오며,RAM
에 데이터를 저장할 때도, 바로RAM
에 쓰는 것 보다는Cache
에 써놨다가RAM
에 적는 방식을 사용합니다.- 하지만 늘 원하는 데이터를
Cache
에 저장해놓을 수는 없으며, 이에 대한 예측 성공에 따라, 속도 차이가 많이나게 됩니다. CPU
가 요청하는 데이터가Cache
에 없는 경우를Cache miss
라고 하며, 이 경우에 상당히 시간이 걸리게 됩니다.
연산 실제 접근 시간 1초로 변환시 시간 1 CPU 연산 사이클 0.4ns 1s L1 Cache 접근 0.9ns 2초 L2 Cache 접근 2.8ns 7초 L3 Cache 접근 28ns 1분 RAM 접근 ~100ns 4분 NVMe SSD접근 ~25 $\mu$s 17시간 일반 SSD접근 50 ~ 150 $\mu$s 1.5일 ~ 4일 HDD 접근 1 ~ 10ms 1 ~ 9달 서울에서 미국 패킷 전송 시간 180ms 14년 - 컴퓨터의 연산은
-
명령어 작성 방법?
CPU
가RAM
에서 데이터를 읽으려면,RAM
의 어디에서 데이터를 읽을지, 말해줘야하며,RAM
에 있는 주소를 전달해줘야합니다.- 어디에서 읽을지 뿐만 아니라, 어디까지 읽을지도 말해줘야 합니다.
- 반대로,
RAM
에 데이터를 저장할 때는, 어디에 저장할 지 말해주면, 전달한 데이터로 변경됩니다. (기존에 있던 데이터는 사라집니다.)
-
CPU가 명령어를 읽어오는 방법
Program
은 실행하는 명령어와 데이터의 집합Program
을 실행하면,RAM
에 해당Program
이 올라가며, 그Program
의 시작점을CPU
에게 알려줍니다.- 그 이후부터는
CPU
가 명령어를 읽어가면 실행하게 됩니다. CPU
는 어디에서 명령어를 읽어야할 지를 저장하는Instruction Pointer
를 보관하는 특별한Register
가 있습니다.CPU
는RAM
에 명령어가 있는 지, 데이터가 있는 지를 알 수 있는 방법은 없습니다. 단순히 쭉쭉 순서대로 처리하기만 합니다.
-
여러 개를 처리할 때?
- 여러 일을 처리하다보면, 메모리 공간이 겹치지 않을까? 하는 생각이 듭니다.
- 이미 다른 쪽에서 사용하고 있는 메모리 공간에 접근하게 되면, 덮어씌워지니 문제가 될 수 있을 것 같습니다.
- 실제 동작 시에는
CPU
가 확인하는 주소값과, 실제RAM
의 주소값을 동일하게 사용하지 않으며,CPU
에서는가상 메모리
를 사용하여, 처리하며, 이를 특별한 변환 과정을 통해물리 메모리
로 변환하여, 실제 저장합니다. - 이러한 방식을
Paging
이라고 합니다. - 변환이 되는 최소 메모리 단위를
Page
라고 하며, 보통 1Page는 4KB입니다.
-
Summary
- 모든 연산은
CPU
의Register
에서 수행되며, 64bit인 경우, 8Byte의 크기를 가집니다. CPU
에서 처리하는 명령어와 데이터는 모두RAM
에서 읽어옵니다.Program
을 실행하는 것은HDD
에 있는 명령어와 데이터를RAM
에 쓰는 것이며,CPU
에는 실행할 첫 명령어의 주소를 전달합니다.CPU
는Cache
가 있어서,RAM
접근 횟수를 줄일 수 있습니다.- 각각의
Program
은 자신이 전체RAM
공간 전체를 사용하는 것처럼 동작합니다. CPU
에서 참조하는 주소값은가상 메모리
주소값입니다.가상 메모리
주소값은 각Program
의 페이지 테이블을 통해물리 메모리
주소값으로 변환될 수 있습니다.
- 모든 연산은
C언어란 무엇인가?
- C언어를 배워야하는 이유?
- 좋은 프로그래머가 되려면, 컴퓨터의 내부 원리를 필수적으로 알아야합니다.
- C언어는 컴퓨터와 연결성이 깊으며, 내부 원리를 이해하는데 큰 도움이 됩니다.
- 많은 언어들이 C언어에서 파생되어, 다른 언어를 쉽게 습득할 수 있습니다.
- 상대적으로 적은 양의 내용만 배워도 됩니다.
- 어떻게 배워야하나?
- 컴퓨터와 친해지면….
- 간단한 프로그램을 직접 구현해보는 것
- C언어를 배우려면 뭐가 필요….?
- 컴퓨터
- 머리
- 노오오오력… (이게 제일 중요)
- 컴파일러
- 컴파일러는 뭐야?
Compiler
는Compile
하는 것입니다.- 컴퓨터는 실제로는 0과 1로 이루어진 기계어만 이해할 수 있습니다.
- 그런데 프로그래밍은 0과 1로만 하지는 않죠
- 이와 같이 프로그래밍 언어와 기계어 사이의 변환을 담당해주는 것이
Compiler
입니다. Windows
에서는MicroSoft Visual Studio
를 이용하여MSVC
를 사용할 수 있습니다.Ubuntu
,MacOS
에서는GCC
를 사용할 수 있습니다.
- 첫 C언어 프로그램
#include <stdio.h>
int main() {
printf("hello world\n");
return 0;
}
- Summary
- C언어는 다른 언어에 비해, 컴퓨터와 가까우며, 이를 통해 많은 것을 배울 수 있음
- 컴퓨터는 0과 1로 이루어진 기계어만 이해할 수 있으며, 따라서 프로그래밍 언어를 기계어로 변환하는
Compiler
가 필요함
C언어 제대로 시작하기
- 이전 코드 분석
#include <stdio.h>
#include
는 뒤에 있는 괄호 안에 있는 파일을 프로그램으로 불러온다는 의미#include <stdio.h>
는stdio.h
를 불러온다는 뜻
int main()
- 이는
main
함수를 정의한 것이며,main
함수는 모든 C 프로그램이 시작하는 부분을 의미 CPU
는main
의 첫 번째 명령어의 주소 값을 전달받을 것으로 예상됨int
는integer
의 줄임말로, 함수가 종료될 때,정수
를 반환한다는 뜻
{
- 중괄호는
main
함수의 시작을 알리며, 중괄호로 묶인 부분까지가main
함수임을 의미 - 중괄호가 열렸다면, 무조건 닫혀야만 오류가 나지 않습니다.
print("hello world\n");
printf
는 괄호 안의 내용을 화면에 출력해주는 함수hello world
라는 내용이 출력되며,\n
은 줄바꿈을 의미- 글자를 화면에 출력한다는 것은 운영체제에 화면에 글자를 뿌려야 한다는 메시지를 보내야하며, 운영체제는 모니터에 메시지를 뿌린다는 것을
CPU
에 얘기해줘야하므로, 꽤나 어려운 과정입니다. - 이를 일일이
CPU
에 설명하는 대신,stdio.h
에 미리 작성되어 있는printf
라는 함수로 사용하는 것 stdio
는Standard Input Output
의 줄임말로, 표준입출력을 뜻합니다..h
로 끝나는 파일은헤더 파일
이라고 부르며, 이를 다른 프로그램에서include
해서 사용할 수 있습니다.
;
- 사실 C언어에서 가장 중요한 것은 ;(세미콜론)입니다.
- 없으면… 무조건 오류가 발생합니다.
- 하지만 모든 부분에 있는 것은 아니며, 상황에 맞게 적용해주어야 합니다.
return 0;
- 0을 반환한다는 뜻
int main
에서main
함수는integer
즉, 정수를 반환한다고 했으며, 0을 반환하고 있습니다.- 0, 1, 2 등의 다른 숫자도 가능하지만, 일반적으로 0은 정상적으로 프로그램이 종료되었음을 의미하며, 1 또는 -1 등은 오류가 발생했다는 것을 의미하는 용도로 사용합니다.
- 주석 넣기
- 주석이란 코드에 설명을 추가하는 것
- 실제 동작하는 프로그램에 영향을 미치지 않습니다.
- C언어에서는 두 가지 방법으로 주석을 넣을 수 있습니다.
/*
과*/
사이에 존재하는 글자들은 주석으로 처리됩니다.//
로 시작하는 줄은 주석으로 처리됩니다.
/* 이 부분은 주석입니다. 뭘 써도 상관없어요 여러 줄에 걸쳐서 쓸 수 있어요 */ // 이건 한 줄에만 적용돼요 printf("hello world"); // 이렇게도 사용할 수 있어요
- Summary
#include <stdio.h>
를 이용하여stdio.h
파일을 코드에 추가할 수 있습니다.main
함수는 프로그램을 시작하는 부분{}
는 함수의 몸체 범위를 지정하는데 사용printf
는 화면에 내용을 출력하는 함수return 0;
는 0을 반환한다는 의미//
or/* */
는 주석으로Compiler
가 무시하며, 코드 설명을 위해 적는 부분
숫자 표현 방법?
- 수는 Number, 숫자는 Digit
- 수는 물질의 양을 나타내는 단위
- 숫자는 이를 기록하기 위한 것
- 숫자를 표현하는 방법을
기수법
이라고 함 - 십진법, 이진법, 16진법
- 253 = $2 \times 10^2 + 5 \times 10^1 + 3 \times 10^0$
- 6 = $4 + 2 = 1 \times 2^2 + 1 \times 2 + 0 \times 2^0 = 110_2$
- 123 = $7 \times 16 + 11 =$ 0x7B
- 십진법은 0 ~ 9, 이진법은 0 ~ 1, 16진법는 0 ~ F (0 ~ 15)를 각 자리수로 사용
- 각 자리수는 $10^n$, $2^n$, $16^n$을 의미
- 숫자 옆에 작게 2가 쓰여진 것은 이진수
- 0x로 시작하는 숫자는 16진수를 의미
- 16진수를 이진수로 변경할 때는 각 16진수의 각 자리를 이진수로 변경한 후, 연결하면 됨
- 반대로 이진수를 16진수로 변환할 때는 4자리씩 끊어서 16진수로 변경하면 됨
- 컴퓨터 메모리의 단위
- 컴퓨터 1개의 메모리 소자는 0 or 1의 값을 가집니다. (Bit)
- 하지만 이는 너무 작으며, 8개의 Bit를 묶어서 1Byte로 나타내며, 주요 단위로 사용합니다. (8Bit = 1Byte)
- 8Bit로 나타낼 수 있는 수는 0 ~ 255로 0x00 ~ 0xFF까지를 표현할 수 있습니다. (총 256개)
WORD
단위는Register
에서 연산이 실행되는 최소 단위를 의미합니다.- 컴퓨터에 따라 다르며, 64Bit 컴퓨터의 경우 1WORD는 64Bit = 8Byte가 됩니다.
- Summary
- 이진법은 0 ~ 1, 십진법은 0 ~ 9, 16진법은 0 ~ F로 숫자를 표현
- 1Byte = 8Bit이며, 1Byte는 0 ~ 255까지의 숫자를 표현할 수 있습니다.
- 컴퓨터는 대부분 4Byte(32Bit) 또는 8Byte(64Bit)단위로 데이터를 처리합니다.
Review
- C++ 공부를 한다더니 왜 갑자기 C를 하고 있냐… 할 수 있을 것 같다.
- 그치만 C++ 코테에서 C의 문법을 사용하는 경우가 간혹 있는 것으로 생각되어서, C가 양이 많지 않으니 함께 보는 것이 좋다는 생각이 들었다.
- 사실 C언어 문법 자체는 이미 한 3번 정도는 봤던터라, 완전 새로운 내용이 있지는 않을 것 같지만, 한번 리프레쉬해주는 차원에서 좋은 것 같다.
- 컴퓨터 구조에 대해서 조금은 더 상세하게 알 수 있는 시간이었던 것으로 보인다.
- 다음 내용에서는 조금 더 실제 코드와 연관되는 부분을 설명할 수 있을 것 같다.