모두코드 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의 문제라면, 휘발성 메모리이므로, 전원을 껐다가 키면 사라집니다.- 늘 새롭게 모든 것을 실행할 수는 없으므로, 비휘발성 메모리가 필요한데 이와 같은 것이
HDDorSSD가 되겠습니다. - 전체적인 흐름을 본다면,
CPU가RAM에 명령어를 저장해두었다가, 꺼내며 연산을 수행하며, 연산 결과에 해당하는 정보를HDDorSSD에 결과로 저장하는 형태입니다. 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번 정도는 봤던터라, 완전 새로운 내용이 있지는 않을 것 같지만, 한번 리프레쉬해주는 차원에서 좋은 것 같다.
- 컴퓨터 구조에 대해서 조금은 더 상세하게 알 수 있는 시간이었던 것으로 보인다.
- 다음 내용에서는 조금 더 실제 코드와 연관되는 부분을 설명할 수 있을 것 같다.