게임프로그래밍 개발 수업/C언어 수업

프로그래밍04 - C언어 n진수 표현과 비트연산, For문

막뇌 2023. 3. 20. 11:59

23-03-20 수업 내용입니다.

Visual Studio 2022 를 사용했습니다.

 

사용한 사진 자료의 출저는 윤성우의 열혈C 프로그래밍 입니다.

====== 오렌지 미디어 ====== (orentec.co.kr)

 

====== 오렌지 미디어 ======

 

www.orentec.co.kr

 

 

예제1, 2진수와 8진수 16진수의 C언어 표현

 

#include<stdio.h>

int main()
{
	int num1 = 0xA7, num2 = 0x43;
	int num3 = 032, num4 = 024;

	printf("0xA7의 10진수 정수 값: %d\n", num1);
	printf("0x43의 10진수 정수 값: %d\n", num2);
	printf(" 032의 10진수 정수 값: %d\n", num3);
	printf(" 024의 10진수 정수 값: %d\n", num4);

	printf("%d-%d=%d\n", num1, num2, num1 - num2);
	printf("%d+%d=%d\n", num3, num4, num3 + num4);

	return 0;
}

출력 화면

 

부호의 표현

 

가장 왼쪽 비트를 MSB(Most Significant Bit)라 한다.

MSB는 부호를 나타내는 비트이다.

∙ MSB를 제외한 나머지 비트는 크기를 나타내는데 사용된다

 

음의 정수를 표현하는 방식은

양의 정수에서 1의 보수를 취하여 1을 더한다.

 

보수란? 

보수(補數)  는 보충 해주는 수를 의미한다고 합니다.

즉, 어떤 목표로 하는 수가 있고,  그 수에 어떤 수를 더하면 목표로 하는 수가 될 때,  그것을 보수라고 하는거죠.1의 보수는 목표가 1입니다.2의 보수는 목표가 2인거죠. 더했을 때 목표가 2가 되는 수.

 

예를 들면 10진법 3이라는 숫자가 있을 때, 10의 보수는 7이고 5의 보수는 2이고, 9의 보수는 6이고..

공식으로 하면 어떤 수 num이 있을 때, N의 보수 = (N - num) 이 되려나요?

복잡해지니까 공식은 

 

보수란?

보충해주는 수인데, 무엇을 보충하냐?

어떤 수(n)를 정해놓고 어떤 수(n)가 되기 위해 보충하는 수 를 n의 보수라고 한다.

이렇게 외워 보려고 합니다.

 

2진수 11001 이 있을 때 1의 보수는 무엇일까요? 각 자리수 별로 1을 만들어 주는 수가 되겠죠?

아래는 1의 보수를 만드는 예시 입니다.

원본 1 1 0 0 1
1의 보수(더했을 때 1이 되는 수) 0 0 1 1 0
더하면 어떻게 되나? 1 1 1 1 1

 

 

아래는 2의 보수를 만드는 예입니다.

원본   1 1 0 0 1
2의 보수(더했을 때 2가 되는 수)   0 0 1 1 1
더하면 어떻게 되나?(2진수로) 앞자리생략 0 0 0 0 0
자리올림되는 수   2 2 2 2 2

2의 보수에서 더했을때 모두 2가 되는데 결국 맨 앞자리가 사라지면 값이  0이 되죠?

컴퓨터에는 뺄셈 기능이 없기 때문에 컴퓨터는 2의 보수형태를 비트화 하여 음수로 사용합니다.

2의 보수형태를 원본양수와 더하면 0이 되니까요.

 

거꾸로 생각하면 음수 형태의 비트에 2의 보수를 구하면

절대값이 나오면서 그게 어떤 수를 의미 하는지 알 수 있게 됩니다.

조금 어렵지만 원래  14라는 정수를 비트로 표현하면 1110 인데, -14를 표현 하려면 2의 보수 형태인 0010 이죠?

 

0010의 2의 보수를 또 구해보면 1110 이 됩니다.

양수의 2의 보수를 구하면 음수를 알 수 있고

음수의 2의 보수를 구하면 절대값을 알 수 있는거죠.

 

 

여기서 공식을 하나 발견 할 수 있는데, 위의 표 2개를 잘 보시면 1의보수와 2의 보수의 차이는 1입니다.

1의 보수의 끝자리에 1을 더하는것으로 2의 보수가 되는것을 볼 수 있습니다.

 

예제 2, 실수 표현의 오차 확인해보기

#include<stdio.h>

int main(void)
{
	int i;
	float num = 0.0f;

	
	for (i = 0; i < 100; i++)
	num += 0.1; //해당 연산을 총 100회 진행하게 된다.

	printf("0.1을 100번 더한 결과: %f\n", num);

	return 0;

}

소수점 자리에 오차가 존재한다. 이는 모든 컴퓨터의 특성이다.


 

비트연산자 (비트이동 연산자)

 

예제3, AND 연산 해보기

#include<stdio.h>

int main(void)
{	
    int num1 = 15; //00000000 00000000 00000000 00001111
	int num2 = 20; //00000000 00000000 00000000 00010100
	int num3 = num1 & num2;
	printf("AND 연산의 결과: %d \n", num3);


	return 0;
}

AND 연산은 논리게이트 때와 같습니다.

둘다 참이면 1, 둘중 하나라도 거짓이면 0을 반환 합니다.

맨끝 비트만 확인 해보면

00001111 과

00010100 를 비교해서 둘다 1인 경우만 출력한다.

 

num1 0 0 0 1 1 1 1
num2 0 0 1 0 1 0 0
num3 0 0 0 0 1 0 0

num3의 값을 비트로 확인해 보면 결국 2진수 100이므로 4이다.

 

 


예제4 OR연산 해보기

#include<stdio.h>

int main(void)
{
	int num1 = 15; //00000000 00000000 00000000 00001111
	int num2 = 20; //00000000 00000000 00000000 00010100
	int num3 = num1 | num2;
	printf("OR 연산의 결과: %d \n", num3);



	return 0;

}

OR 연산은 둘중하나만 true 면 true, 둘다 false면 false다

num1 0 0 0 0 1 1 1 1
num2 0 0 0 1 0 1 0 0
num3 0 0 0 1 1 1 1 1

2진수 11111 = 10진수로 표기할 경우 31이다. 그러므로 num3 값의 출력은 31이다.


 

예제5 XOR 연산 해보기

#include<stdio.h>

int main(void)
{
	int num1 = 15; //00000000 00000000 00000000 00001111
	int num2 = 20; //00000000 00000000 00000000 00010100
    int num3 = num1 ^ num2;
	printf("XOR 연산의 결과: %d \n", num3);


	return 0;
    
}

num1 0 0 0 0 1 1 1 1
num2 0 0 0 1 0 1 0 0
num3 0 0 0 1 1 0 1 1

XOR 연산은 OR연산과 관련이 없습니다.

이름이 비슷하다고 해서 연관이 있을것이라고 착각하지 말아요.

Exclusive OR를 줄여서 XOR 이라고 하며

Exclusive 에는 독점적인, 베타적인 이라는 뜻이 있습니다. 까칠한 놈들이예요.

 

즉, 둘이 사이가 안좋고 한놈이 회로를 독점해야만 참이 된다. 서로 사이가 안좋다고 외우자.

둘이 죽이 잘맞아서 둘다 참이거나 둘다 거짓이면 안된다. (둘이 친구면)거짓이고.

서로 사이가 안좋아서 둘중 하나만 참인 경우(둘이 싸우고 있는 경우)참인 것이다.

따라서 num3 의 비트 연산 결과는 2진수로 11011이고

10진수로는 1+2+8+16 = 27이 된다.


 

예제6 NOT 연산 해보기

#include<stdio.h>

int main(void)
{
	int num1 = 15; //00000000 00000000 00000000 00001111
	int num2 = ~num1;
    printf("NOT 연산의 결과: %d \n", num2);
	

	return 0;
}

 

NOT연산의 경우 모든 비트를 반전 시키는 역할을 하기 때문에

부호를 담당하는 비트까지 반전 됩니다.

따라서 부호가 바뀐채, 비트는 1의 보수형태가 된다고 보시면 됩니다.

더해서 1이 되는 수, 아시죠? 그냥 0과 1 반전 시켜 주면 됩니다.

num1 0 0 0 0 1 1 1 1
num1의 1의 보수
=num2
1 1 1 1 0 0 0 0
num2의 절대값
= num2의 2의 보수
0 0 0 1 0 0 0 0

2번째 행에서 절대값이 16인걸 알 수 있죠?

따라서 NOT 연산의 결과는 -16 이 되는 겁니다.

 

 


비트의 왼쪽 이동

 

#include<stdio.h>

int main(void)
{
	int num = 15;	//00000000 00000000 00000000 00001111

	int result1 = num << 1;	//num의 비트 열을 왼쪽으로 1칸씩 이동
	int result2 = num << 2;	//num의 비트 열을 왼쪽으로 2칸씩 이동
	int result3 = num << 3; //num의 비트 열을 왼쪽으로 3칸씩 이동

	printf("1칸 이동 결과: %d \n", result1);
	printf("2칸 이동 결과: %d \n", result2);
	printf("3칸 이동 결과: %d \n", result3);
	
	return 0;

}

비트를 한칸씩 이동해 줍니다.

00000000 00000000 00000000 00001111

 

num 00000000 00000000 00000000 00001111 15
result1 00000000 00000000 00000000 00011110 30
result2 00000000 00000000 00000000 00111100 60
result3 00000000 00000000 00000000 01111000 120

신기하게도 비트를 한칸씩 밀 때마다 크기가 2배씩 증가하네요.

10진수에서 0이 하나씩 더 붙는거랑 같은 방식이라고 보면 될것 같네요.n진수에서 자리를 하나 밀면 n배만큼 숫자가 증가합니다.

자릿수가 하나 더 늘어나는 거니까 당연하다고 봐야 할까요? 처음엔 잘 이해가 안갔는데

4진수 8진수 전부다 그렇네요.

 

 

 


비트의 오른쪽 이동

#include<stdio.h>

int main(void)
{

	int num = -16;
	printf("2칸 오른쪽 이동의 결과: %d \n", num >> 2);
	printf("3칸 오른쪽 이동의 결과: %d \n", num >> 3);
    return 0;

}

 

오른쪽으로 이동하면 자릿수가 하나씩 없어지는 것이기 때문에 위에서 왼쪽으로 이동 할 때 × n을 했다면

이번엔 ÷ n을 한것과 같다고 생각하면 됩니다.

 


문제 풀어보기

정답 보기

더보기

문제1 정답 
4비트는 16가지  데이터 수를 표현 가능 0000 ~ 1111 까지 (의 4승)
1바이트로 표현 가능한 수 = 1바이트는 8비트이므로 00000000 ~ 11111111까지 256가지 표현 가능(2의 8승)
4바이트로 표현 가능한 수 = 4바이트는 32비트임 (2의 32승) 4,294,967,296가지

 

문제2 정답

1
2
4
8
16
32
64
128

 

문제3 정답

16+1 = 17
2+32+128 = 162
1+2+4+16+32+64+128 = 247

 

 

더보기

문제 1 정답

각각 64+8+4+2+1, 32+16+2+1 이다.
각각 10진수로 79, 51 이다.

 

문제 2 정답

절댓값을 구하기 위해 2의 보수 형태를 취해 본다.

절댓값이 각각 01010111, 00010000 이므로

각각 -87, -16 이다.

 

 

더보기
#include<stdio.h>

int main(void)
{
	int num1;
	int num2;

	printf("정수를 입력하시오: ");
	scanf_s("%d", &num1);

	num2 = ~num1+1;
    // NOT 연산자를 사용해서 비트값을 반전시킨 후(1의 보수) 1을 더해서 절대값을 맞춰준다(2의 보수)
	printf("부호를 반전하면 :%d이다.", num2);


	return 0;
}

 

 

반복문 For / While / Do While 문 이해하기

 

For문 예제1

#include<stdio.h>

int main(void)
{

	//for문
	int dan = 1;
	for (int i=1; i<10; i++)
	{
		printf("%3d × %3d = %3d \n", dan, i, dan * i);
	}



	return 0;

}

 


For문 예제 2

#include<stdio.h>

int main(void)
{
	//1부터 100까지 전부 더해보기
	int result = 0;
	for (int i = 1; i <= 100; i++)
		result += i;
	printf("결과 출력: %d \n", result);
	

	return 0;
}

for문 이후의 문장이 한줄인 경우 중괄호{}를 생략할 수 있다.

 


For문 예제3

홀수의 합, 짝수의 합을 따로 구해 보기

#include<stdio.h>

int main(void)
{
	//홀수의 합, 짝수의 합을 따로 따로 구해 보기
	int holsu = 0;
	int jacsu = 0;
	
	for (int i = 0; i <= 100; i++)
	{
		if (i % 2 == 1)
			holsu += i;
		if (i % 2 == 0)
			jacsu += i;
	}
	printf("홀수의 합:%d\n", holsu);
	printf("짝수의 합:%d\n", jacsu);



	return 0;

}

 


For문 예제4

for문을 2중으로 활용하여 구구단을 만들어 보자

scanf_s 를 활용하여 n단부터 최대 9단까지 출력 하도록 만들어보자

더보기
#include<stdio.h>

int main(void)
{
	int cur;
	int is;
	printf("몇단부터 몇단까지 출력 할까요");
	scanf_s("%d %d", &cur,&is);
	
	for (int i = cur; i <= is; i++)
	{
		for (int j = 1; j < 9; j++)
			printf("%d × %d = %d\n", i, j, i * j);
		
		printf("\n");
	}

	return 0;

}

 

 

 

오늘 배운것

C언어에서 2,8,16진수를 어떻게 표현 할 수  있는지 배웠다.

1의 보수, 2의 보수를 통해 컴퓨터가 비트로 음수, 양수를 표현할 때, 어떤식으로 계산 과정을 거치는지 알게 되었다.
1비트는 2진수 1자리이며, 1바이트는 8비트로 이루어 졌다. 정수 형태(int)는 4바이트 형태의 자료형이라는걸 알게 되었다.

비트단위 연산자를 통해 2진수 형태로 비트 연산을 하는 방법을 배웠다.

반복문중 한가지인 For문을 여러 형태로 연습하면서 사용 방법을 숙달하는 과정을 진행 했다.