Search

Chapter 1 ~ Chapter 10

Created
2020/06/10
tag
C
씹어먹는 C 언어
컴파일러
음수 표현
2의보수

1. C 언어를 배워야 하는 이유

가장 중요한 부분이 아닌가 싶다. 꽤 오랜 시간동안 대학 생활을 하면서 내 머리 속에 따라다니는 것들 중 하나이다. 대학교 새내기 시절에 C 언어를 처음 배웠을 때, C 언어를 왜 배워야 하는지 알지 못했다. 그럼에도 선배들이나 주변 사람들, 교수님들까지도 C 언어를 알아둬서 나쁠 것 없고 오히려 잘하면 매우 좋다는 얘기를 들으니 아~ 그런가보다 하면서 해왔던 것 같다. 심지어 가장 의문이었던 점은 C 언어, C++을 배우면 무엇을 할 수 있는가였는데, 이 질문을 할 때마다 들었던 대답은 무엇이든 다~ 할 수 있다 였다.
그래서 그냥 했던 것 같다.
시간이 지나서 전공을 배우고, 과제를 하고, 텀 프로젝트를 하고, 개발을 조금씩 하고 보니 다른 언어보다 C 언어, C++이 참 중요하다는 생각이 많이 들었다. C 언어, C++은 뭔가 필요한게 있으면 직접 구현을 해야하는 경우가 허다했고, 혹여나 라이브러리를 쓰더라도 다른 언어들에 비해서 그 동작 과정과 원리에 대해서 아주 정확하게 알고 있어야 했던 것 같다. 즉, 구현하려는 것에 대해 명확한 이해가 없거나 구현 능력이 조금만 떨어져도 제대로 사용하기가 어려웠던 기억이 난다.
또한 전공을 배우면서 C 언어, C++은 컴퓨터 사이언스와 떼려야 뗄 수 없는 관계였다. 깊은 지식을 바탕으로 하기 위해선 이를 모르면 깊이 있는 공부가 힘든 것 같았다.
다른 언어를 배운다고 해서 깊이 없는 지식을 갖고 있다거나 구현 능력이 떨어진다고 말하고 싶은 것이 아니다.
나는 뛰어나진 않아도, 모자라지 않은 소프트웨어 엔지니어 혹은 개발자가 되고 싶다. 따라서 지금 당장 프로덕션을 만드는 기술 보다는 컴퓨터 내부 동작을 이해하고 이와 가장 맞물리며 동작하는 언어를 통해 근본을 아는 것이 가장 필요했다. 컴퓨터 사이언스에 대해 정확히 이해하고 싶고, 깊이 있는 지식을 갖고 싶었다. 나와 비슷한 상황이라면, 위에서 내가 느낀 것들이 C 언어 혹은 C++을 배워야 하는 이유가 될 수 있지 않을까 싶다.

2. 컴파일러의 필요성

C 언어 자체는 기계가 이해할 수 있는 언어라기 보다, 사람들이 이해할 수 있는 High-Level 언어이다. 따라서 우리가 작성한 코드들은 기계가 이해할 수 있는 언어로 바꿔줘야 한다. 이 역할을 컴파일러가 해준다. C 언어C++의 경우, 아래의 그림과 같이 전처리기를 거친 코드가 컴파일러를 통해 기계가 이해할 수 있는 어셈블리어로 변환된다.

3. 음수를 표현할 때 부호화 절대치를 이용하지 않고 2의 보수 (2's Complement)를 사용하는 이유

우리는 코딩을 하다보면 음수를 사용할 때가 있다. 컴퓨터는 우리가 사용하는 10진수2진수로만 인식하기 때문에 0과 1만으로 양수음수를 모두 표현해야 했다. 과거 CPU 개발자는 부호를 통해서 양수음수를 구분하고자 했고, 이 부호를 컴퓨터의 Most Significant Bit (최상위 비트)로 이용하기로 했다. 따라서 MSB가 0일 때는 양수를, MSB가 1일 때는 음수를 나타내게 되었다. 이렇게 부호 비트를 이용하여, 음수를 표현하기 위해 MSB에 단순히 1만 붙이는 것을 부호화 절대치 라고 한다.
아래의 예시는 모두 4비트를 기준으로 작성하겠다.
부호화 절대치를 이용하여 MSB를 1로 두어 -3이라는 음수를 나타내면 1011이 된다. 사실일까? 실제로 컴퓨터에서 인식하는 -32진수로 확인해보면 1101이다. 실제 컴퓨터에서 -31011이 아니라 1101으로 나타낸 것은 2의 보수라는 것을 이용했기 때문이다. 왜 부호화 절대치는 이용하지 않는 것일까?

1) 0의 두 가지 표현

0을 비트로 나타내면, 0000이다. +0-0은 모두 0을 의미하기 때문에 부호화 절대치를 이용하면 0에 대해서 0000, 1000이라는 두 가지 표현이 생겨버린다. 0은 프로그래밍에서 굉장히 중요한 의미를 갖는다. 참과 거짓에 대한 판별을 할 때를 예로 들어보면, 0은 false를 의미하기 때문에 0을 표현하는 값이 두 개가 된다는 것은 불필요한 비교를 한 번 더 한다는 것을 의미하게 된다.

2) 컴퓨터의 연산 방식

컴퓨터의 뺄셈, 곱셈, 나눗셈은 모두 가산기(Adder)덧셈 연산을 기반으로 동작하는 만큼 덧셈은 모든 연산에 있어서 가장 기본이다. 부호화 절대치음수를 표현하게 되면 이런 연산에 어려움들이 생긴다.
예를 들어, 1-3을 더하는 것은 00011011을 더하는 것과 같고 결과는 1100이 된다. 여기서 결과로 나온 1100-2를 의미하는데 부호화 절대치에서의 -21010이다. 올바른 결과를 만들기 위해서는 순서를 맞춰 뺄셈을 이용하여, 1011에서 0001을 빼야 1010이라는 제대로 된 값이 나온다. 이를 통해 볼 수 있는 것은 양수와 음수 사이 연산을 덧셈으로 처리하지 못한다는 것두 수의 연산 시 순서가 중요하다는 것이다. 따라서 양수음수덧셈 연산을 위해서 별도의 감산기를 두어 뺄셈을 수행하는 것이 필요하며, 덧셈에 기초하고 있는 다른 연산들 역시 가산기만으로 연산이 불가능하고 가산기감산기를 두어 연산을 수행해야 한다.
단순히 하드웨어를 하나 더 두고 말고의 문제가 아니라 상황에 맞게 동작할 수 있도록 회로를 구성하는 것 역시 큰 문제이다. 혹여나 회로를 잘 구현하더라도 비교 연산에서 어려움이 생길 수 있다. -2-3의 비교 시에 -2가 더 큰 것이 되어야 하는데 비트로 비교를 하면 10101011을 비교하게 되고 1010보다는 1011이 더 크기 때문에 -2보다 -3이 더 큰 현상이 발생한다. 따라서 이를 구분할 수 있게도 해줘야 한다.
따라서 부호화 절대치를 이용했을 때 여러 문제들이 발생할 수 있기 때문에 2의 보수현 상태의 비트를 모두 반전 시키고 1을 더하는 방식을 이용하게 되는 것이다.
1의 보수를 이용할 때는 부호화 절대치가 갖고 있는 양수음수 사이 덧셈도, 음수끼리 비교 연산도 해결이 되지만 여전히 문제가 있다. 여전히 0의 표현 방식이 두가지라는 것덧셈 과정에서 캐리가 발생했을 때 LSB에 1을 더해줘야 해서 이를 처리하는 회로를 둬야 한다는 것이다. 따라서 2의 보수를 이용한다. 2의 보수를 이용하면 0의 표현 방식이 두 가지라는 것도 해결이 되며, 1의 보수에서 캐리를 처리해야 하는 문제도 사라진다.

4. Reference