IT/C/C++

변수와 형

루카스강 2015. 1. 11. 18:20

변수 : 변수란 말 그대로 변수이다. 변하는 숫자. 수학을 배운 사람이라면 누구나 알고 있는 그 x가 맞다.


 변수의 선언


  C언어에서는 이 변하는 숫자인 x를 먼저 선언해야지 사용할 수 있다.

  변수를 선언하는 방법은 매우 간단하다.


  int a;  // 변수의 형 이름;


이런식으로 선언하면 된다.

변수의 형에 대해서는 조금 나중에 배우기로 하고 이것만은 기억하도록 하자. 변수의 형, 한칸 띄고 변수의 이름 그리고 세미콜론.


이렇게 변수를 선언하면 컴퓨터는 메모리 안에 공간을 할당하여 데이터를 읽고 쓴다. (컴퓨터를 조금이라도 아는 사람이면 메모리는 RAM이라는 것을 알 것이다.)


즉 변수를 선언하는 것은 메모리 번지를 직접 사용하는 것이 아니라 프로그래머가 좀 더 쉽게 메모리를 읽고 쓸 수 있도록 별도로 이름을 붙여놓은 것이라 할 수 있다. 


변수를 선언할 때는 몇 가지 규칙만 지키면 된다.

일반적으로 변수를 선언한다면 다소 상관이 없을 수도 있다.


  1. 변수 명의 길이에는 제약이 없지만, 컴퓨터가 인식하는 데는 한계가 있다. 그래서 제약이 없는 것 같지만 실제로는 어느 정도까지만 인식하고 뒤 이름은 버리는 것과 같다. 따라서 기억하기도 쉽지 않게 길게 쓰는 것보다는 3~10자 내외로 짧게 작성하도록 하자. (63글자까지는 인식한다.)


  2. 변수는 대소문자를 구분한다. 따라서 대소문자를 일관되게 하는 것이 좋다. 즉 apple 과 Apple 은 다른 변수이다.


  3. 첫 글자는 영문자이거나 _ 만 올 수 있다. ( 즉 숫자가 와서는 안된다.)


  4. 영문자, 숫자, _ 로만 작성할 수 있다. (띄어쓰기가 안되므로 굳이 작성하고 싶다면 i_love_you 처럼 _를 활용하도록 하자.)


  5. 예약어와 키워드(int, char, if, for, while 등)은 사용할 수 없다.



● 변수의 형


  컴퓨터는 변수를 읽을 때, 메모리의 번지를 참조한다고 했다. 하지만 실제로 컴파일러가 변수를 참조할 때는 메모리 번지를 참조하는 것이 아니라 번지에 기억된 값을 참조한다. 따라서 프로그래머가 "변수 a의 값을 읽어와라, 변수 a는 123번지이다."라고 명령을 내려도 컴파일러는 123번지부터 어디까지 읽어야 하는지 알 수가 없다. 따라서 저장된 메모리 번지의 값을 해석할 방법이 필요하다. 정수와 실수의 값의 형태가 다르듯 메모리에 기록되는 방법도 당연히 다르다. 따라서 정확하게 변수를 사용하기 위해서는 변수의 형에 대해서도 알아야 한다.



  C언어에서 제공하는 변수의 형을 보면 다음과 같다.

    1. void   // 아무것도 지정되지 않는 형이다.

    2. int      // integer 정수형이다.

    3. char   // character  문자형이다.

    4. bool  // Boolean  불형이라고 하며 참과 거짓을 저장한다.

    5. float  // floating point 실수형이다.

  


이 외에도 유도형 변수인 배열과 구조체, 공용체, 포인터, 함수형이 있지만 그것에 대한 것은 나중에 배우도록 하자.


1. Void 형

   이 타입은 값은 있지만 어떤 형인지 정해지지 않은 형이다. 메모리에 기록은 되지만 읽어 들일 때 어떤 형식으로 읽을 것인지 지정을 해주어야 한다.



2. Int 형

   가장 유명(?) 한 형이라고 할 수도 있다. 정수를 나타낸다. 기본적으로 4바이트 (32bit)의 크기를 가지지만 최근에는 8바이트(64bit)의 크기를 가지기도 한다. 즉 int 형은 사용하는 컴퓨터의 cpu 크기에 따라 달라진다. (필자는 64bit 컴퓨터를 사용하고 있지만 편의를 위해 진행되는 강의에서는 int 형을 4바이트로 사용할 것이다.)


응용된 형으로는 short int (2바이트),  long long int( 8바이트 ) 가 있다.

변수의 형을 응용해서 쓰는 이유는 변수의 크기에 따라 나타낼 수 있는 범위가 다르기 때문이다.

정수형 변수인 int 형은 데이터를 저장할 때 이진법을 사용한다.


10진법을 2진법으로 바꾸는 방법은 모두 알고 있을 것이다.  2진법으로 1은 1₂ 2는 10₂ 4는 100₂ 10은 1010₂ 이다. 정수형인 int는 10진법을 2진법으로 바꾸어 메모리에 바로 저장한다. 예를들어 10을 4바이트 메모리에 저장한다고 하면 메모리에는 다음과 같이 저장이 된다.


0

0

1


그렇다면 음수는 어떻게 표현할까?  -10을 부호비트만 바꾼다면 이렇게 표현이 될 것이다. (정수형에서 최상단 비트는 부호비트로 사용된다.

(0은 양수, 1은 음수)


 0


하지만 부호비트만 바꾸는 방식을 사용하면 연산시에 큰 문제를 초래하게 된다.

위 두 값을 더하면 10 + (-10) 을 더하면 0이 반환이 되어야 하지만 다음과 같이 될 것이다.


1


-20이 되었다. 따라서 음수를 표현 할 때는 2의 보수법을 사용한다. 1의 보수를 취해준 다음 1을 더하는 방법이다.

1의 보수를 취하는 방법은 그냥 양수일 때의 수를 0을 1로 1을 0으로 반대로 바꾸어 주면 된다.

즉 모든 수를 바꾼 다음 1을 더해주면 된다.

2의 보수법을 사용하여 -10을 표현하면 다음과 같이 될 것이다.




이를 10이랑 더한다면

 

0

0

1

+
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

 0

 0

 0

 0

 0

 0


사실 32비트를 초과해서 1이 하나 더 튀어나왔지만 메모리를 초과했으므로 컴퓨터는 무시하게 된다. 따라서 메모리에는 0이 제대로 나타나게 되었다.


그렇다면 정수형으로 표현할 수 있는 범위는 어떻게 될까. 부호비트를 제외하고 나머지 비트를 전부 1로 채운다면

2147483647이다. 반대로 가장 작은 수는 -2147483648 이 될 것이다.


하지만 상황에 따라 2147483647 보다 큰 수를 표현해야 할 때가 올 수도 있고, 이렇게 큰 범위는 필요가 없을 때도 있다.

그럴 때는 변수의 크기를 적절히 바꾸어 가며 상황에 맞추어 사용하면 된다.


만약 양수만 사용하고 싶은데 범위가 모자르다면 unsigned 를 int 앞에 붙여 부호비트를 사용하지 않게 할 수도 있다. 

부호비트를 사용하지 않으므로 범위는 2배가 늘어날 것이다.

나이나 성적을 저장하고 싶은데 굳이 부호가 없어도 상관이 없으므로 unsigned 형을 쓸 수도 있다.


크기를 8바이트로 바꾸는 방법도 있다. long long int 를 사용하면 그만큼 범위가 넓어질 것이다.


굳이 4바이트를 사용하지 않아도 되는 상황이 올 때가 있다. 년도나 온도를 저장하는데 굳이 메모리를 낭비해 가면서 4바이트나 차지하는 int 형을 쓸 필요가 없다. short 형이나 short int 형을 사용하면 될 것이다.




3. char 형


문자를 표현하는 형이다. 문자를 여러개를 합쳐서 문장 즉 문자열을 표현할 때 사용하기도 한다. 

기본적으로 크기는 1바이트다.(8bit) 그래서 -128 ~ 127 까지의 수를 표현할 수 있다.

char 형을 흔히 문자형이라고 알고 있는 사람이 많은데 사실은 1바이트짜리 정수형 변수이다.


printf 는 %c 를 만나면 해당 숫자에 해당하는 문자를 출력해주는데 사실 이 변수가 int 가 오든 char 이 오든 상관없이 해당 숫자에 맞는 문자를 출력하기 때문이다. 


문자를 출력할 때는 ASCII 코드를 따른다. 사실 여러가지 인코딩 방법이 있지만 통상적으로 이 아스키 코드 방식을 많이 사용한다.


10

16

문자

10

16

문자

10

16

문자

10

16

문자

10

16

문자

0

0

Null

47

2F

/

68

44

D

89

59

Y

110

6E

n

7

7

Bell

48

30

0

69

45

E

90

5A

Z

111

6F

o

8

8

BS

49

31

1

70

46

F

91

5B

[

112

70

p

9

9

Tab

50

32

2

71

47

G

92

5C

\

113

71

q

10

A

LF

51

33

3

72

48

H

93

5D

]

114

72

r

13

D

CR

52

34

4

73

49

I

94

5E

^

115

73

s

32

20

공백

53

35

5

74

4A

J

95

5F

_

116

74

t

33

21

!

54

36

6

75

4B

K

96

60

`

117

75

u

34

22

"

55

37

7

76

4C

L

97

61

a

118

76

v

35

23

#

56

38

8

77

4D

M

98

62

b

119

77

w

36

24

$

57

39

9

78

4E

N

99

63

c

120

78

x

37

25

%

58

3A

:

79

4F

O

100

64

d

121

79

y

38

26

&

59

3B

;

80

50

P

101

65

e

122

7A

z

39

27

'

60

3C

<

81

51

Q

102

66

f

123

7B

{

40

28

(

61

3D

=

82

52

R

103

67

g

124

7C

|

41

29

)

62

3E

>

83

53

S

104

68

h

125

7D

}

42

2A

*

63

3F

?

84

54

T

105

69

i

126

7E

~

43

2B

+

64

40

@

85

55

U

106

6A

j

127

7F

Del

44

2C

,

65

41

A

86

56

V

107

6B

k

 

 

 

45

2D

-

66

42

B

87

57

W

108

6C

l

 

 

 

46

2E

.

67

43

C

88

58

X

109

6D

m

 

 




(출처 : www.soen.kr)


아스키 코드는 문자를 하나하나 숫자와 매칭해놓았기 때문에 문자를 정수로 사용할 수도 있고, 정수를 문자로 사용할 수도 있다.


예를들어 문자 'A' 를 %d 로 출력하면 65라는 숫자가 나오고, 65를 %c로 출력하면 문자인 A가 나오는 것이다.




4. bool 형


논리형인 bool형은 참과 거짓 둘 중하나를 가지는 변수이다. 사실 C문법은 논리형을 별도의 기본형 타입으로 인정하지 않지만, 많은 컴파일러들은 bool형을 만들어서 사용한다. 사용자가 직접 정의해서 사용해도 된다. 


typedef int BOOL;

#define TRUE 1

#define FALSE 0


정의를 하는 define에 대해서는 나중에 배울 것이다. 하지만 한눈에 봐도 참과 거짓을 정의하고 있다는 감은 올 것이다. 위 코드는 BOOL 이라는 형을 만들어서 사용한 것인데, 참과 거짓 1과 0만을 사용하는데 int 형을 사용하는 것은 메모리 낭비가 심하다. 그래서 C++ 에서는 별도로 bool 이라는 논리형을 지정해 주었고, BOOL과 달리 1바이트로 지정되어 있다. 정리를 하자면


BOOL 형은 4바이트 짜리 논리형

bool 형은 1바이트 짜리 논리형


비주얼 스튜디오 컴파일러를 사용하는 경우에는 C++ 컴파일러도 같이 사용하기 때문에 bool형이 정의 되어 있지만, .cpp 확장자가 아닌 .c 확장자에서는 사용하지 못한다. 리눅스 C에서 표준 gcc를 사용하는 경우에는 따로 헤더파일을 include 해주어야 하기 때문에 조심해서 사용하자. 가장 마음이 편한 것은 직접 정의해서 사용하는 것이다.




5. float 형


float 형은 실수를 표현할 수 있는 형이다. 크기는 4바이트며 더 큰 실수를 표현할 수 있는 double 형도 있다. (8바이트)


하지만 컴퓨터는 0,1 로 이루어져 있기 때문에 실수형을 표현하기에는 무리가 있다. 따라서 실수는 부동 소수점이라는 방식으로 특이하게 표현한다.

예를들어 123.45 를 표현할때는 공학적으로 1.2345 * 10^2 이렇게 표현한다. 실수를 정수부와 소수부로 나누는 것이 아니라 실수부와 가수부로 가누는 것이다. 123.45 에서 지수는 2이고 가수는 12345이다.

이렇게 나누어서 float 형인 4바이트에는

부호ㅣ              지수부(8)          ㅣ                                                          가수부 (23)                                                     ㅣ

 1

 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


double 형은  1,11,52 로 나눈다.

따라서 double 형이 가수부가 더 크므로 정밀도가 크다고 할 수 있다.


지수부와 가수부에 데이터를 채워넣는 법은 IEEE754 방식을 사용한다.


부호비트는 예전과 같이 0은 양수이고 1은 음수이다.


지수는 n이라고 했을 때 가수부에 2^n을 곱한다. (10진수를 2진수 실수로 표현해야 하기 때문에 머리가 조금 아플수도 있다..) float 형에서 지수부는 8비트이므로 -127 ~ 128까지 쓸 수 있다. 지수부는 부호비트를 가지고 있지 않고 따로 127 바이어스를 적용한다. 하지만 -127과 128은 0과 무한대를 표현하기 위해 남겨두므로 최대 표현 범위는 2^127 인 10^38 정도이다.


가수는 각 자리수에 2의 음수 거듭승으로 가중치가 부여되어 있다. 가수는 항상 1과 2사이여야 하기 때문에 2^0승을 항상 더해준다.


123.45 를 IEEE754 방식으로 표현해보자

먼저 123을 2진수로 변환해준다. 1111011

0.45 를 2진수로 변환해 줄때는 2를 곱해서 나온 앞자리를 계속 때오면 된다.

0.45 * 2 = 0.9     ---- 0

0.9   * 2 = 1.8    -----1

0.8   * 2 = 1.6   ----- 1

0.6   * 2 = 1.2   ----- 1

0.2   * 2 = 0.4   ----- 0

0.4   * 2 = 0.8  ------0

0.8   * 2 = 1.6  ------1

. . . . . .

1111011.01110011.... 가 나왔다.

( 수를 잘못 정했다... ) 실제로 나머지가 없을 때까지 계산을 하기 때문에 실수를 처리하는 방법은 느리다.

가수부와 지수부로 표현하면

1.11101101110011....  * 2^6  이 되고, 6이 지수부, 1.11101101110011 가 가수부로 들어가게 된다.


부호는 양수이므로 부호비트는 0이 되며, 지수부는 6에 127바이어스를 적용해 127를 더하면 133이 되고, 2진수로 표현하면 10000101.

가수부는 1때고 가중치 부분만 들어가면 된다.

부호 ㅣ       지수 (8)                   ㅣ                                          가수 (23)                                                                         ㅣ

0 

 1

0 

0 

0 

0 

1 

0 

1 

 1

1 

1 

0 

1 

1 

0 

1 

1 

1 

0 

0 

1

1 

0 

0 

1 

1 

0 

0 

1 

1 

0


데이터가 한정되어 있기 때문에 나머지가 딱 떨어지지 않더라도 뒤에가 잘리기 마련이다. 그래서 실수는 정확히 표현할 수 없으며 데이터의 크기에 따라 정밀도가 한정되어 있다.

float 형은 대략 6~7 자리

double 형은 대략 15자리이다.


따라서 실수를 사용할 때는 정밀도를 염두해 두어야 하고, 6자리 이상의 정밀도가 필요한데도 float 형을 사용하면 오차가 발생할 수 있으니 항상 유의해야 한다.




'IT > C/C++' 카테고리의 다른 글

C언어 개론  (0) 2014.12.25