자료형(Data Type)은 데이터의 종류를 의미합니다. 다른 프로그래밍 언어에도 자료형이라는 개념이 존재합니다. C프로그래밍은 메모리(RAM)에 데이터를 옮기고 데이터가 정수, 실수, 문자, 논리 등 어떠한 종류인지 지정을 해줘야 하기 때문에 개념이 존재합니다.
C언어 기본 자료형은 4가지 종류가 있으며 용량과 용도에 따라 세분화된 표기가 존재합니다.
- 논리형: Bool
- 정수형: char, short, int, long, long long
- 실수형: float, double, long double
- void형: void
이 글은 정수형과 실수형에 대해서만 알아보겠습니다. 밑은 예문이며 순서대로 각 줄의 코드를 해석하겠습니다.
정수형의 종류와에 그에 대한 설명입니다.
- char: 1byte(8bit) 범위의 정수를 ASCII Code의 문자로 반환하여 다룹니다. 반환 최대값은 0~255 사이의 정수입니다.
- (예시) char c = 66; => B, char c = 1; => r, char c = 'D' - 1; => C
ASCII Code란? 컴퓨터에서 문자를 표현하는 표준 코드 체계로 각 문자에 대해 고유 숫자값이 존재함.
- short: 2byte(16bit) 범위의 정수를 다룹니다 .
- int: 4byte(32bit) 범위의 정수를 다룹니다.
- long: 4byte(32bit) 범위의 8byte(64bit)까지의 정수를 다룹니다. <주로 4byte(32bit) 범위 사용>
- long long: 8byte(64bit) 범위의 정수를 다룹니다 .
실수형은 표현이 무한대지만 컴퓨터의 공간은 무한하지 않아 실수 표현을 최대한 크게 하기 위해 소수점은 고정시키지 않고 유동적으로 둥둥 떠다닐 수 있게 사용한대는 개념, 부동소수점(Floating Point)이 등장합니다. 그 종류와 그에 대한 설명입니다.
- float: 4byte(32bit) 범위의 실수를 다룹니다. / 3.4E+/-38(7개의 자릿수)
- double: 8byte(64bit) 범위의 실수를 다룹니다. / 1.7E+/-308(15개의 자릿수)
- long double: double 이상의 8byte(64bit) 범위의 실수를 다룹니다. / double과 동일하나 정밀도가 더 높음.
- 실수 자료형은 출력값이 기본적으로 소수점 6자리까지 표현됩니다.
이제 예시문입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
#include <stdio.h>
int main()
{
// 자료형(Data Types)
// 변수(Variables)
// 자료형 변수명 = 초기값;
// 변수 선언(Variables Declaration)
// Character(문자)
// ASCII Code Table
char c = 'D' - 1;
printf("c: %c (%p) [%d byte]\n", c, &c, sizeof(char));
short int s = 1;
// Half-Integer
printf("s: %hi (%p) [%d byte]\n", s, &s, sizeof(short));
// Integer
int i = 10;
// Decimal
printf("i: %d (%p) [%d byte]\n", i, &i, sizeof(int));
long int l = 100L;
printf("l: %li (%p) [%d byte]\n", l, &l, sizeof(long));
long long int ll = 1000LL;
printf("ll: %lli (%p) [%d byte]\n", ll, &ll, sizeof(long long));
///////////////////////////////////////
int val = 'A';
printf("val: %c\n", val);
// var: variables, val: value
// MSB: Most Significant Bit, Sign Bit
// LSB: Least Significant Bit
// 2의 보수법
// 10000101 (-5)
// 00000101 (5)
// 11111010 (1의 보수)
// 11111011 (+1)
unsigned char var = 255u;
printf("var: %d\n", var);
/////////////////////////////////////
// 실수
// 고정소수점(Fixed-Point)
// Single Precision Floating-Point(부동소수점)
float f = 3.1f;
// Literal Constant
// 3.7f = 3.1f;
printf("f: %f (%p) [%d byte]\n",
f, &f, sizeof(float));
// Double Precision Floating-Point
// 배 정밀도 부동소수점
double d = 3.14;
printf("d: %lf (%p) [%d byte]\n",
d, &d, sizeof(double));
long double ld = 3.145L;
printf("ld: %Lf (%p) [%d byte]\n",
ld, &ld, sizeof(long double));
// 부동소수점 오차
float result = 0.0f;
for (int i = 0; i < 1000; ++i)
{
result += 0.001f;
}
printf("result: %f\n", result);
return 0;
}
|
이전 글에서 다뤘던 건 간략하게 해석하겠습니다.
#include <stdio.h>: stdio.의 헤드(h)파일을 포함시키겠다.
int main(): main() 함수가 종료할 때 정수형(int) 값을 반환하겠다.
밑 줄부턴 차근차근 해석하겠습니다.
char c = 'D' - 1
- 문법: 자료형 변수명 = 초기값; (이하 생략)
- 자료형: char(문자형)
- 변수명: c
- 초기값: 'D'는 ASCII Code에서 68을 의미하고 거기서 -1 = 67, char문의 특징으로 ASCII Code값으로 67의 C가 출력 <char문 제외한 다른 자료형은 ASCII Code 문자 대신 숫자가 표기됨. ex) short s = 'D' - 1 => 67(C)
printf("c: %c (%p) [%d byte]\n", c, &c, sizeof(char)); / <자료형인 char 대신 변수명인 c를 써도 가능>
- 문법: c: %c-c, (%p)-&c, [%d byte]-sizeof(char) / (c)
- 해석: 출력값은 c:로 시작해 변수 c의 값, 주소, char타입의 크기를 byte단위로 반환하고 뒤에 byte를 붙여 출력하라. \n로 다음 줄로 이동해라.
- 출력값: c: C (주소) [1 byte]
short int s = 1; <short는 short int의 단축입니다. 둘 다 사용가능하며 이유는 int가 정수 자료형의 중심이라고 생각하면 편합니다.>
- 자료형: short int (질문)
- 변수명: s
- 초기값: 1
printf("s: %hi (%p) [%d byte]\n", s, &s, sizeof(short)); / <자료형인 short 대신 변수명인 s를 써도 가능>
- 문법: s: %hi-c, (%p)-&c, [%d byte]-sizeof(short) / (s)
- 해석: 출력값은 s:로 시작해 변수 s의 값, 주소, short타입의 크기를 byte단위로 반환하고 뒤에 byte를 붙여 출력하라. \n로 다음 줄로 이동해라.
- 출력값: s: 1 (주소) [2 byte]
int i = 10;
- 자료형: int
- 변수명: i
- 초기값: 10
printf("i: %d (%p) [%d byte]\n", i, &i, sizeof(int); / <자료형인 int 대신 변수명인 i를 써도 가능>
- 문법: i: %d-i, (%p)-&i, [%d byte]-sizeof(int) / (i)
- 해석: 출력값은 i:로 시작해 변수 i의 값, 주소, int타입의 크기를 byte단위로 반환하고 뒤에 byte를 붙여 출력하라. \n로 다음 줄로 이동해라.
- 출력값: i: 10 (주소) [4 byte]
long int l = 100L; <long은 short int의 단축입니다. 둘 다 사용가능하며 이유는 short int와 동일합니다.>
- 자료형: long int
- 변수명: l
- 초기값: 100L / L은 리터럴 접미사(Literal Constant)로 l의 값 100을 int가 아닌 long으로 해석하도록 명시적 지정시켜 줍니다.
printf("l: %li (%p) [%d byte]\n", l, &l, sizeof(long); / <자료형인 long 대신 변수명인 l를 써도 가능>
- 문법: l: %d-l, (%p)-&l, [%d byte]-sizeof(long) / (l)
- 해석: 출력값은 l:로 시작해 변수 l의 값, 주소, long타입의 크기를 byte단위로 반환하고 뒤에 byte를 붙여 출력하라. \n로 다음 줄로 이동해라.
- 출력값: l: 100 (주소) [4 byte] (long은 주로 4byte를 사용하는 타입이기 때문에)
long long int ll = 1000LL; <long long은 long long int의 단축입니다. 둘 다 사용가능하며 이유는 위와 같습니다.>
- 자료형: long long int
- 변수명: ll
- 초기값: 1000LL / LL은 리터럴 접미사(Literal Constant)로 ll의 값 1000을 int가 아닌 long long으로 해석하도록 명시적 지정시켜 줍니다. 출력값엔 LL은 생략됩니다.
printf("ll: %lli (%p) [%d byte]\n", ll, &ll, sizeof(long long); / <자료형인 long long 대신 변수명인 ll를 써도 가능>
- 문법: ll: %d-ll, (%p)-&ll, [%d byte]-sizeof(long long) / (l)
- 해석: 출력값은 ll:로 시작해 변수 ll의 값, 주소, long long타입의 크기를 byte단위로 반환하고 뒤에 byte를 붙여 출력하라. \n로 다음 줄로 이동해라.
- 출력값: ll: 1000 (주소) [8 byte]
이제 val과 var문입니다. val = value, var = variable입니다.
int val = 'A';
- 자료형: int
- 변수명: val
- 초기값: 65 / 'A'는 ASCII Code의 값으로 65를 뜻한다.
printf("val: %c\n", val);
- 해석: 출력값에 val:로 시작해 변수 val의 값 65를 %c로 ASCII Code로 반환하여 출력하라. \n로 다음 줄로 이동해라.
- 출력값: val: A
unsigned char var = 255u;
- 자료형: char
- 변수명: var
- 초기값: 255 / u는 unsigned의 u로 부호 -값을 제외한 0~255을 표현함.
printf("var: %d\n", var);
- 해석: 출력값에 var:로 시작해 변수 var의 값 255를 %d로 10진수로 반환하여 출력하라. \n로 다음 줄로 이동해라.
- 출력값: val: 255
위의 unsigned에 대해 간단히 설명하겠습니다.
- sigend: 타입별로 표현할 수 있는 범위에 부호 -를 포함한 음수값까지 포함하여 범위를 지정하는 것입니다. -최솟값 ~ +최댓값
- unsigned: 타입별로 표현할 수 있는 범위에 부호 -음수값을 제외한 범위를 지정하는 것입니다. 0~최댓값
- 예시: signed char: -127~127의 정수, unsigned char: 0~255의 정수. (둘 중 아무것도 쓰지 않으면 자동 signed로 판단합니다.)
이제 실수입니다.
float f = 3.1f
- 자료형: float
- 변수명: f
- 초기값: 3.1 / f는 리터럴 접미사(Literal Constant)로 float 자료형에서 소수를 저장할 때 f를 붙이지 않으면 같은 실수 자료형인 double로 판단해 출력할 때 오류가 발생할 수 있어 float에게 할당한다는 것을 컴퓨터에 알려주는 기능입니다. 출력값엔 f가 포함되지 않습니다.
printf("f: %f (%p) [%d byte]\n", f, &f, sizeof(float); / <자료형인 float 대신 변수명인 f를 써도 가능>
- 문법: f: %d-f, (%p)-&f, [%d byte]-sizeof(float) / (f)
- 해석: 출력값은 f:로 시작해 변수 f의 값, 주소, float타입의 크기를 byte단위로 반환하고 뒤에 byte를 붙여 출력하라. \n로 다음 줄로 이동해라.
- 출력값: f: 3.100000 (주소) [4 byte]
double d = 3.14;
- 자료형: double
- 변수명: d
- 초기값: 3.14
printf("d: %lf (%p) [%d byte]\n", d, &d, sizeof(double); / <자료형인 double 대신 변수명인 d를 써도 가능>
- 문법: d: %lf-d, (%p)-&d, [%d byte]-sizeof(double) / (d)
- 해석: 출력값은 d:로 시작해 변수 d의 값, 주소, double타입의 크기를 byte단위로 반환하고 뒤에 byte를 붙여 출력하라. \n로 다음 줄로 이동해라.
- 출력값: d: 3.140000 (주소) [8 byte]
long double ld = 3.145L;
- 자료형: long double
- 변수명: ld
- 초기값: 3.145 / L는 리터럴 접미사(Literal Constant)로 long double에게 할당한다는 것을 의미합니다. L이 없다면 double에게 할당됩니다. 출력값엔 L이 포함되지 않습니다.
printf("ld: %Lf (%p) [%d byte]\n", ld, &ld, sizeof(long double); / <자료형인 long double 대신 변수명인 ld를 써도 가능>
- 문법: ld: %Lf-ld, (%p)-&ld, [%d byte]-sizeof(long double) / (ld)
- 해석: 출력값은 ld:로 시작해 변수 ld의 값, 주소, long double타입의 크기를 byte단위로 반환하고 뒤에 byte를 붙여 출력하라. \n로 다음 줄로 이동해라.
- 출력값: ld: 3.145000 (주소) [16 byte]
밑은 printf 줄에 사용된 헷갈리는 용어들 정리입니다.
- %c char 문자형의 값을 출력하기 위한 형식 지정자
- %i integer로 정수라는 뜻, 정수로 출력하기 위한 형식 지정자
- %d decimal로 10진수라는 뜻, 10진수 형태로 출력하기 위한 형식 지정자
- %f float로 float 자료형의 값을 출력할 때 사용하는 형식 지정자로 소수점 6자리까지 출력합니다. 만약 소수점을 지정하고 싶으면 %nf로 표현
- %li long integer로 long 자료형의 값을 출력할 때 사용하는 형식 지정자
- %lf long float로 double 자료형의 값을 출력할 때 사용하는 형식 지정자로 소수점 15~17자리까지 출력합니다. 소숫점 지정을 안 할 시 15자리로 자동 출력됩니다.
- %Lf long double 자료형의 값을 출력할 때 사용하는 형식 지정자
- %p pointer로 출력값의 주소를 표기할 때 사용하는 형식 지정자
- 정수형은 부호를 정할 수 있는 signed, unsigned가 추가로 존재합니다.
남은 코드는 실수 자료형 float타입을 이용한 부동소수점 오차와 관련된 예제입니다.
float result = 0.0f;
for (int i = 0; i < 1000; ++i)
{
result += 0.001f;
}
printf("result: %f\n", result);
해석본은 이렇습니다.
- float 타입의 result 변수를 0.0f로 초기화합니다. f는 float의 리터럴 접미사입니다.
- for은 반복문으로 i가 1000보다 작은 동안 result에 0.001f를 계속 더합니다.
- result의 값을 %f로 float 자료형의 값을 출력(printf)합니다.
위의 해석대로라면 출력값은 result: 1.000000이 나옵니다.
그러나, 부동소수점의 오차로 인해 주어진 환경(컴파일러, 시스템 등)에 따라 출력값이 result: 0.999999 / result: 1.000001이 나올 수도 있습니다. 이러한 결과를 이해하려면 부동소수점과 그와 다른 개념인 고정소수점을 알고 이해하는 것이 필요합니다.
- 고정소수점은 소수점이 고정되어 있는 방식입니다.
- 부동소수점은 소수점이 필요에 따라 이동하여 더 넓은 범위의 숫자를 표현하는 방식입니다.
이에 대해선 10진수의 값을 2진수로 변환하는 과정을 알아야 이해가 됩니다만, 이건 따로 다루겠습니다. 위의 예제를 단순하게 쉽게 이해하자면 result에 반복해서 더하는 0.001f의 값이 '0.001000000...'일 수도 있고, '0.0010010110...' 일 수도 있습니다. 그래서 출력값이 변화할 수 있다고 이해할 수 있습니다.
끝
'프로그래밍 C언어' 카테고리의 다른 글
연산자(Operators)와 형변환(Type Casting) (0) | 2024.08.09 |
---|---|
변수(Variable)와 상수(Constant) (0) | 2024.08.08 |
고정소수점과 부동소수점의 이해 (0) | 2024.08.08 |
printf "Hello World" (1) | 2024.08.06 |
프로그래밍의 시작 Visual Studio 설치 (0) | 2024.08.06 |