- 제 1장- C언어의 세계로2025년 02월 02일 04시 11분 09초에 업로드 된 글입니다.작성자: sonotree
Contents
1) 왜 C언어를 배워야하는가?
2) C언어 본격 맛보기
3) 주석
4) 컴퓨터에서 수를 표현하는 방법
01. 왜 C언어를 배워야 하는가?
적당히 잘하는 프로그래머가 목표라면 굳이 컴퓨터 내부가 어떻게 돌아가는지 몰라도 상관 없다.
하지만 좋은 프로그래머가 되려면, 컴퓨터의 내부 원리를 아는 것이 필수적이다.
C언어를 배운다면 컴퓨터 내부 원리를 더 쉽게 이해할 수 있다.
많은 언어들이 C언어에서 파생되어 생겨났기 떄문에 C어너를 배우면 다른 언어들을 공부하는데 도움이 된다.흔히 언어를 가장 쉽게 배우는 방법은 친구를 사귀는 것이라는 말을 들을 수 있다.
C언어도 마찬가지이다. 우리는 C언어를 매우 잘 하는 컴퓨터 친구와 함께 C언어를 배워나갈것이다.
C언어를 가장 빨리 습득하는 방법은 강좌에서 배운 내용을 토대로 간단한 프로그램을 직접 만들어 보는 것이다.
컴파일>
컴파일(compiling)은, 주어진 언어로 작성된 컴퓨터 프로그램을 다른 언어의 동등한 프로그램으로 변환하는 프로세스이다. 일반적으로 컴파일러는 C++과 같은 고급 언어로 작성된 코드를 이진코드 또는 기계 코드라고 하는 실행 가능한 코드로 변환한다.
-> 간단히, 컴파일러를 통해 전처리된 소스코드 파일을 어셈블리어 파일로 변환하는 과정이라고 생각해도 됨
추가로 링크(Link)는, 여러개로 분리된 소스파일을 최종 실행 가능한 파일을 만들기 위해 서로 연결해주는 작업이며, 빌드(Build)는 소스코드 파이을 실행 가능한 소프트웨어로 만드는 과정이다.
컴파일러>
컴파일러(compiler) 즉 번역기는, 특정 프로그래밍 언어로 쓰여 있는 문서를 다른 프로그래밍 언어로 옮기는 언어 번역 프로그램을 말한다. 일반적으로 고급 프로그래밍 언어를 실행 프로그램으로 만들기 위해 저급 프로그래밍 언어(ex,어셈블리어)로 바꾸는데 사용된다.
원래의 문서를 소스 코드 또는 원시 코드라고 부르고, 출력된 문서를 목적 코드라고 부른다. 목적 코드는 주로 다른 프로그램이나 하드웨어가 처리하기에 용이한 형태로 출력되며, 이런 원시코드 -> 목적 코드로 옮기는 과정을 컴파일이라고 한다.
아래는 컴파일러 종류에 대한 사진이다. 간단히 살펴보자.
프리프로세서(pre-processor)는, 실제 코드를 컴파일하기 전에 사전 준비 작업을 수행하는 컴파일러이다. 예를 들어 C언어로 코드를 작성 할 경우 헤더 파일을 정의하여 여러 소스 파일에서 사용할 수 있게 할 수 있는데, 이때 프리프로세서가 이 헤더파일 부분을 실제 소스 코드로 대체해주는 사전 작업을 하게 된다.
컴파일러(compiler)는 고급 언어를 저급 언어로 번역해준다. 여기서의 저급언어는 어셈블리어이다.
어셈블러(assembler)는 위에서 언급한 어셈블리어를 기계어(0과 1)로 변환하는 역할을 수행한다.
인터프리터(interpreter)는 고급 언어를 한 줄씩 번역해서 실행 결과를 바로 출력하는 컴파일러이다. 대표적으로 Python이 인터프리터를 사용한다.
컴파일, 어셈블리...이다 많이 햇갈린다. 하지만 좋은 소식은 우리가 쉽게 컴파일러들을 구할 수 있다는 것이다. 우리는 마소에서 무료료 배포하는 Visual C++ 2020 Community를 사용할것이다. 이걸 다운받으면 위의 컴파일러가 자동으로 설치된다.
첫 프로그램>
#include <stdio.h> int main() { printf("Hello, World! \n"); return 0; }
이제 F7(솔루션 빌드)를 눌러 컴파일을 진행해준다. 아래 사진과 같이 나오면 성공적으로 빌드된것이다.
그리고 F5(디버깅 시작) 또는 Ctrl + F5(디버그 하지 않고 시작)을 눌러 프로그램을 실행해보자.
+) 디버깅이란, 소프트웨어 개발 과정에서 발생하는 오류를 찾아 수정하는 프로세스이다.
F5 Ctrl + F5 <정리>
우리는 컴파일러를 사용해 컴파일 -> 링크 -> 빌드 과정을 거친다. 컴파일러란 고급 프로그래밍 언어를 저급 프로그래밍 언어(어셈블리어)로 바꾸어주는 "번역 프로그램"이며 우리는 이 컴파일러를 가지고 고급 프로그래밍 언어를 저급 프로그래밍 언어로 변환하는 과정인 컴파일을 거친다.
고급 언어는 컴파일 과정을 거쳐 저급 언어(어셈블리어)로 변환되며, 어셈블러를 사용하여 어셈블리 과정을 거친 후 기계어로 변환된다.
02. C언어 본격 맛보기
Hello, Wolrd 프로그램 분석하기>
#include <stdio.h>
stdio.h는 Standard Input Output Header의 약자로, 표준 입출력 헤더이다.
stdio.h라는 파일을 이 파일에 포함시키므로써, 입력장치인 키보드로부터 입력을 받아들이고 출력장치인 화면에 내용을 출력하도록 하는것이다.
int main()
정수 형을 반환하는 main 함수이다. 항상 함수를 선언할 때 "[함수명] ()"로 선언하는것과 같은것이다.
모든 C프로그램은 이 mian에서부터 시작된다.
printf("Hello, World! \n")
printf는 화면에 괄호 안의 내용을 출력할 수 있게 해주는 함수이다. printf 함수에 의해 "Hello, World!"라는 문자열이 출력된다.
printf 함수가 어떤 과정을 거쳐 화면에 글자로 출력되는 것일까?
-> 화면에 글자를 출력하는 것은 매우 쉬워보이지만, 실재로는 매우 복잡한 과정을 거친다. 일단 OS에 자신이 화면에 글자를 뿌려야 한다는 메시지를 보내야 하고 또 OS는 하드웨어(모니터)에 이를 출력한다는 것을 이야기 해주어햐 하기 때문이다.
-> "Hello. Wolrd!"라는 짧은 문자열을 화면에 출력하기 위해 위의 긴 과정을 코드에 모두 작성하는것은 상당히 비효율적이다. 따라서 우리는 위 모든 내용을 포함하고 있는 파일인 stdio.h 파일을 사용한다!!
03. 주석(comment)
주석(comment)는 자신의 코드에 대해 설명하는데 사용된다. 긴 주석과 짧은 주석이 있다.
주석은 우리가 코드를 이해하기 위해 필요한 부가적 요소이기 때문에 컴파일러는 이 주석을 무시한다. 즉 주석은 컴파일러가 완전히 무시하고 오직 사람의 편의를 위해서만 존재한다.
/*이건 긴 주석*/ //이건 짧은 주석
지금 코드를 쓰고있는 시점에서 내응을 잘 안다고 주석을 생략하는 경우 -> 한 달 뒤 ???상태가 되며 2배로 고생함
주석이 잘 작성되어 있는 코드 -> 몇년 뒤에 코드를 읽어도 잘 이해가 됨
04. 컴퓨터에서 수를 표현하는 방법
수(Number) & 숫자(Digit) >
수(number)란, 어떤 물질의 양을 나타내는 단위이며 숫자(digit)란, 이를 기록할 수 있도록 시각화 한 것이다.
예를 들어 사과가 100개(수)있다는 사실을 보여주기 위해 사과를 100개 그려야하면 상당히 번거로울 것이다. 그래서 우리는 '100'이라는 숫자를 써서 사과가 100개 있다는 것을 보여준다.
놀라운 점은 우리가 0~9까지의 숫자만(digit)을 이용해서 수(number)를 표시할 수 있다는 것은 아니라는 것이다! 이는 사과를 나타내기 위해 '사과' 뿐만 아니라 'apple', 'リンゴ’'라고 써도 되는 것과 비슷하다. 우리는 0과 1만을 이용해 수를 표시할 수 있고 100개의 숫자를 이용해 수를 표시할 수도 있다.
이렇게 수를 표현하는 방법을 기수법(Numeral system)이라고 한다.
수학적 배경 지식 - 밑과 지수 >
2를 100번 곱한것을 \(2^{100}\)이라는 것은 아니까 넘어가자.
지수에서 가장 중요한 사실은 \((number)^{0}=1\)이라는 사실이다.
어떻게 숫자를 한 번도 안 곱했더니 1이 될수가 있냐! 라고 말 할수 있겠지만, 이는 수학자들 사이에 약속처럼 정의한 값이다.
수학은 "복잡한 것을 단순히"라는 목적 하에 발전해왔다.
만일 이 값을 1이라 하지 않는다면 여러 지수들에 관련된 중요한 법칙들이 성립되지 않는다. 다시말해 어떤 수의 0승 한 것이 1이라 생각하는 것은, 다른 법칙들이 만족되기 위해 그렇게 약속한 것이다... 이다.
십진법, 이진법 16진법 >
십진법 >>
아라비아 숫자를 사용하는 우리는 수를 나타내기 위해 10개의 숫자를 이용하는 십진법(decimal)을 이용하고 있다.
우리는 253이라는 숫자가 나오면 \(253 = 2*10^{2} + 5*10^{1} + 3*10^{0}\)이라고 생각한다.
주목해야할 부분은 한 자리수가 늘어날 때 마다 그 자리를 나타내는 숫자에 10이 곱해진다는 것이다. 1의자리에서는 3이라는 숫자에 1이 곱해지고 10의자리에서는 5라는 수에 10이 곱해지고 100의 자리에서는 2라는 숫자에 100이 곱해진다. 이것이 바로 십진법의 가장 큰 특징이다.
또 중요한 특징으로 십진법은 10개의 숫자를 사용한다는 것이다. 0부터 9까지의 숫자말이다. 297, 109 등 모든 십진수 숫자들은 0~9 사이의 숫자들로만 이루어져있다.
이진법 >>
위의 아이디어를 적용시키면 이진법도 쉽게 이해할 수 있다.
컴퓨터는 0과 1(on off)인 두 종류의 숫자밖에 표현하지 못한다. 그렇다면 컴퓨터로 253이라는 숫자는 어떻게 표현될까?
십진법에서 사용한 규칙을 그대로 적용하면 된다. 쉬운 예시로 먼저 살펴보자.
\(6 = 4 + 2 = 1*2^{2} + 1*2^{1} + 0*2^{0} = 110_{2}\)
십진법에서 한 자리 늘어날 때마다 10이 곱해졌다면, 이진법에서는 한 자리가 늘어날 때마다 2를 곱하면 된다.
그럼 이제 253을 이진법으로 나타내보자.
\(253 = 128 + 64 + 32 + 16 + 8 + 4 + 1\)
\(= 1*2^{7} + 1*2^{6} + 1*2^{5} + 1*2^{4} + 1*2^{3} + 1*2^{2} + 0*2^{1} + 1*2^{0}\)
-> 이진수를 십진수로 바꾸는것은 쉽다. 자리수가 하나 올라갈 때마다 2가 곱해지는 것만 생각하면 되기 때문이다. 하지만 관건은 십진수를 어떻게 이진수로 바꾸는가이다. 어려워보일 수 있지만 매우 간단하다. 그냥 십진수를 2로 나누는 연산을 하면 되기 때문이다.
16진법 >>
하지만 이진법으로 숫자를 표현하면 너무 길어져 가독성이 떨어진다. 그래서 프로그래머들은 보통 16진법을 사용한다. 16진법 또한 위에서 살펴봤던 패턴을 그대로 적용하면 된다.
따라서 123은 \(123 = 7*16 + 11 = 7*16^{1} + 11*16^{0} = 0x7B\)로 표현된다.
- A=10
- B=11
- C=12
- D=13
- E=14
- F=15
-> 16진수를 10진수로 바꾸는 것도 그냥 자릿수가 올라갈 때마다 16을 곱해주는 방식으로 진행하면 된다. 0x7B의 경우 11에 1을 곱하고 7에 16을 곱하면 된다.
-> 그러면 이제 16진수를 2진수로 바꾸어보자.
이때는 단순히 16진수의 각 자리수를 (반드시)4자리 이진수로 변환해주면 된다.
※예외적으로 맨 앞자리는 굳이 4자리 맞출 필요 없음0x7B의 경우 1111011(0111/1011)로 표현된다. 맨 앞자리 숫자인 7의 경우 0111이기 때문에 굳이 4자리수를 맞추지 않고 111으로 쓴다.
-> 이진수를 16진수로 변환하는 것도 간단하다. 뒤에서부터 4자리씩 끊어서 읽으면 된다. 1111011의 경우 111/1011이므로 0x7B가 된다.
컴퓨터 메모리의 단위 >
컴퓨터에 데이터를 저장하는 공간은 크게 두 부류로 나눌 수 있다.
- 휘발성 메모리(ex. Ram(random access memory)): 컴퓨터를 종료하면 데이터가 날아감
- 비휘발성 메모리(ex. Rom(read only memory), 하드디스크): 컴퓨터를 종료해도 데이터가 날아가지 않음
Ram은 Rom에 비해 비해 속도가 매우 빠르다. 왜냐하면 램의 경우 데이터에 랜덤하게 접근할 수 있는데 롬(하드디스크 or CD)의 경우 순차적으로 접근해야 하기 때문이다.
이런 빠른 메모리의 특성 때문에 컴퓨터는 대부분의 데이터들을 메모리(앞으로 Ram=메모리로 부를거임)에 보관해 놓고 작업을 한다. 물론 중요한 데이터들은 틈틈히 하드디스크에 저장해 날아가지 않게 한다.
컴퓨터의 한 개의 메모리 소자는 0 또는 1의 값을 보관할 수 있다. 이 이진수 한 자리를 Bit라고한다. 따라서 1bit로는 1 또는 0을 나타낼 수 있다.
하지만 이는 너무 작은 양이고 우리는 보통 1보다 훨씬 큰 수를 다루기 때문에, 사람들은 8bit를 뭈어서 Byte라고 부른다.
8 비트로 나타낼 수 있는 최대 수는 0 ~ 255까지 총 256개이다.
00000000 ~ 11111111 = 0 ~ 155 = 0 ~ 0FF컴퓨터에서 연산을 담당하는 CPU에는 레지스터(register)라는 작은 메모리 공간이 있는데, CPU는 이곳에 값을 불러다 놓고 연산을 수행한다. 이러한 레지스터의 크기는 컴퓨터 상에서 연산이 실행되는 최소 단위라고 볼 수 있고 이 크기를 워드(Word)라고 부른다.
32비트 컴퓨터의 경우 1워드 = 32비트 = 4바이트
64비트 컴퓨터의 경우 1워드 = 64비트 = 8바이트가 된다.다음글이 없습니다.이전글이 없습니다.댓글