이번에는 변수와 자료형에 대해서 다뤄 보려고 한다.
C언어는 내가 가장 좋아하고 많이 사용한 언어다. 내가 알고있는 다양한 내용을 담다보니 글이 길어졌지만 한 번 읽어보면 꽤 도움 될 거다.
- 변수란?
변수(variable)는 어떤 값을 저장 할 수 있는 메모리 공간이다.
a = 5 라고 선언했을 때 a가 5를 저장한 변수가 된다.
- 자료형이란?
16(정수), 1.45(실수), 'h'(문자)를 변수에 담을때 자료형(data type)에 따라 구분해줘야한다.
아래 코드 처럼 a,b 변수 앞에 자료형(int, float)을 붙여줘서 정수인지, 실수인지 구분한다.
int a = 16; //정수
float b = 3.14 //실수
- 자료형의 종류
아래는 자료형의 종류를 나타낸다.
일단 이런게 있구나 정도로 대충 훑어보고 넘어가면 된다.
구분 | 자료형 | 예시 |
정수형 | char | 단 하나의 문자 ex) h |
short | 정수형인 숫자 ex) 1577 | |
int | ||
long | ||
long long | ||
실수형 | float | 소수점 있는 숫자 ex) 3.141592 |
double | ||
나열형 | enum | 정수를 대신해서 사용하는 별명, int와 크기가 같음. ex) 월요일 ~ 일요일 |
무치형 | void | 자료형이 없음을 명시적 선언 |
- 자료형의 크기가 가지는 범위
아래 표는 각 자료형이 나타낼 수 있는 범위를 보여준다.
이제부터 나올 설명들을 볼때 이 표를 참고하면된다.
같은 정수형, 실수형이라도 크기(byte)에 따라서 자료형이 나뉜다.
이렇게 많은 자료형이 있는 이유는 메모리를 낭비하지 않고 효율적으로 사용하기 위해서다.
예를 들어 같은 정수형이라도 int 대신 short를 쓰면 2byte를 절약 할 수 있다.
자료형
|
크기(byte)
|
범위
|
char
|
1
|
-128 ~ 127
|
unsigned char
|
1
|
0 ~ 255
|
short
|
2
|
-32768 ~ 32767
|
unsigned short
|
2
|
0 ~ 65535
|
int
|
4
|
-2147483648 ~ 2147483647
|
unsigned int
|
4
|
0 ~ 4294967295
|
long
|
4
|
-2147483648 ~ 2147483647 |
long long
|
8
|
-9223372036854775808 ~ 9223372036854775807
|
float
|
4
|
1.175494e-38 ~ 3.402823e+38
|
double
|
8
|
2.22507e-308 ~ 1.79769e+308
|
long double
|
16
|
3.362103e-4932L ~ 1.189731e+4932L
|
- unsigned란?
unsigned에 대해 알아보자.
short 풀네임은 signed short로 signed가 생략 된거다. 즉 부호(±) 가 있다는 거다.(int, char, long도 마찬가지)
unsigned 는 부호(±)가 없다는 뜻이다.
따라서 short와 unsigned short가 표현 할 수 있는 총 개수는 65536개로 같지만
short는 -32768 ~ -1 과 0 ~ 32767 까지 나타 낼 수있으며,
unsigned short는 부호가 없으므로 0 ~ 65535 까지 나타낼 수 있다.
- overflow
만약 변수 선언시 자료형의 범위를 넘게 되면 어떻게 될까?
예를 들어 int 자료형은 크기가 4byte라서 약 -21억 부터 +21억 사이까지 표현가능하다.(위에 표 참고)
아래 코드 처럼 int의 최대 범위를 넘은 30억으로 a 변수 선언시 overflow가 발생하여 엉뚱한 값이 저장된다.
따라서 자료형의 범위 내의 값을 저장하도록 주의해야 한다.
overflow (오버 플로우) : 최대 저장 공간의 범위를 넘어서면 발생하는 현상
int a = 3000000000 //30억이므로 overflow 발생
- byte 개념 잡기
byte 개념을 모르는 사람을 위해 설명하는 부분이니 아는 사람은 다음으로 가면된다.
unsigned char 로 예를 들어 보자.
unsigned char 는 크기가 1byte로 0 ~ 255까지의 범위를 가져 총 256개의 수를 표현할 수 있다.(0을 포함하니까)
이제 1byte가 어떻게 256개를 표현 할 수 있는지 알아보자.
1bit는 0아니면 1로 표현한다.(2진법)
1bit가 8개 모이면 8bit가 되고
8bit = 1byte와 같다. 이건 꼭 외워야 한다.
8bit 를 2진수로 나태내면 최대값 1111 1111과 최소값 0000 0000 이 된다.
1111 1111과 0000 0000 을 10진수로 바꾸면 255, 0이 된다.
따라서 1byte는 0 ~ 255까지 총 256개를 표현할 수 있게되는거다.
2byte도 마찬가지로
16bit = 2byte
16 bit를 2진수로 나타내면 최대값 1111 1111 1111 1111 ~ 최소값 0000 0000 0000 0000
1111 1111 1111 1111 를 10진수로 변환 하면 65535
따라서 2byte = 0 ~ 65535 범위까지 표현할 수 있다.(unsigned short 의 범위다.)
ps. 진법 계산기 돌려보면서 꼭 이해하고 넘어가자.
- char
char는 character(문자)의 약자다.
char는 크기는 1 byte로 -128 ~ 127의 범위를 가진다.
그런데 어떻게 숫자로 문자를 표현한다는 걸까?
그건 바로 아스키코드(ASCII)를 사용한다.
아래 그림은 아스키코드(ASCII)다.
10진수 0 ~ 127가 각각의 문자에 대입된다.
예를들어 10진수 65 는 문자 A가 되는 방식이다.
따라서 엄밀히 따지면 char는 정수형이다.
만약 "A p p l e" 문자 5개를 쓰면 5byte의 메모리를 차지한다.(char = 1byte니까)
하지만 한국어는 환경에 따라 한 문자에 2byte 또는 3byte의 메모리를 차지하게 된다.
따라서 "안 녕 하 세요" 문자 5개를 쓰면 각각 10byte 또는 15byte의 메모리를 차지하게 된다.
아스키 코드 127개 안에 외국어가 들어갈 수 없기 때문이다.
- 문자 출력하기
문자 A를 출력하는 예제다.
문자를 선언 할때는 문자를 ' ' (작은 따음표)로 감싸줘야한다.
또한 출력할 때는 %c 를 사용해 ch 변수의 문자 A를 출력해 준다.
#include <stdio.h>
int main()
{
char ch = 'A';
printf("%c", ch);
}
결과
A
- 아스키코드 10진수 출력하기
아스키코드의 10진수 값 출력도 가능하다.
%c은 문자 출력용이므로 정수를 출력하기 위해 %d를 사용한다.
\n 는 줄바꿈(엔터) 역할이다.
#include <stdio.h>
int main()
{
char ch = 'A';
printf("%d\n", ch); //65 (아스키 코드 10진수 값)
char ch2 = ch + 5; //65 + 5
printf("%d\n", ch2); //70
}
결과
65
70
아스키코드에서 A = 65이므로 ch변수는 65가 출력된다.
ch2 는 65(A) + 5 = 70이 된다.
- int
int는 integer(정수)의 약자다. 따라서 정수만 선언할 수 있다.
int는 정수형이기 때문에 %d 를 사용하여 변수를 출력해준다.
#include <stdio.h>
int main()
{
int a = 5;
printf("%d", a);
}
결과
5
아래 처럼 변수 선언 후 덧셈, 뺄셈, 곱하기, 나누기 연산이 가능하다.
#include <stdio.h>
int main()
{
int a = 5;
int b = 10;
printf("%d\n", a + b); //더하기
printf("%d\n", a - b); //빼기
printf("%d\n", a * b); //곱하기
printf("%d\n", a / b); //나누기
}
결과
15
-5
50
0
- int vs long
아래 표를 보면 int와 long 둘다 정수형인데 크기까지 4byte로 똑같다.
그럼 하나만 쓰면 되지 왜 굳이 int, long을 둘다 사용하는 걸까?
이유는 이렇다.
현재 프로세서 아키텍처는 64bit를 사용하지만 과거에는 16bit, 32bit를 사용했다.
C언어가 처음 개발 됐을때 int는 가장 효율적으로 처리 할 수 있는 자료형을 목표로 개발 되었다.
따라서 int는 특별한 취급을 받았고 프로세서 아키텍처에 따라 가장 효율적인 크기를 갖게 되었다.
아래가 C언어 처음 나왔을 때 16bit 운영체제에서 사용한 크기다.
//16bit 운영체제
short : 2byte
int : 2byte
long : 4byte
32bit 운영체제가 되고 int는 가장효율적인 4byte가 되었다.
// 32bit 운영체제
short : 2byte
int : 4byte
long : 4byte
문제는 64bit 운영체제에서 발생했다.
long의 풀네임은 long int로 int를 생략한다. long int를 직역하자면 더 긴 정수형으로 long은 int보다 크기가 더 커야만 한다.
하지만 int의 크기가 가장 효율적인 8byte가 되면 기존 long(4byte)보다 커지게 되는 모순적인 현상이 발생하게 된다.
따라서 64bit 아키텍처에서 int를 4byte로 사용하고 long을 8byte로 크기를 늘리는 선택을 했다.
// 64bit 운영체제
short : 2byte
int : 4byte
long : 8byte
하지만 문제가 있다.
다른 64bit 운영체제는 long의 크기가 8byte지만 windows에서는 long의 크기가 4byte로 사용된다.
따라서 현재 int와 long의 크기는 똑같은 4byte가 된거다.
OS | Application Bit (binary) | long size |
Windwos (x86-64) | 32 bit | 4 byte |
64 bit | 4 byte | |
OS X (x86-64) | 32 bit | 4 byte |
64 bit | 8 byte | |
Linux (x86-64) | 32 bit | 4 byte |
64 bit | 8 byte | |
Aix (PowerPC) | 32 bit | 4 byte |
64 bit | 8 byte | |
HP-UX (IA-64) | 32 bit | 4 byte |
64 bit | 8 byte | |
Solaris (Sparc) | 32 bit | 4 byte |
64 bit | 8 byte |
요지는 이렇다.
만약 windows, Linux에서 똑같은 프로그램을 돌려야한다면 개발 시 long의 사용은 자제하는게 좋다.
또한 int와 long은 32bit, 64bit에 따라 크기가 달라지므로 아키텍처에 따라 자료형 사용을 고려할 필요가 있다.
출처 1 : https://hackerpark.tistory.com/entry/C%EC%96%B8%EC%96%B4-int-%EC%99%80-long-%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%B4-%EB%8B%A4%EB%A5%BC%EA%B9%8C-short-short-int-int-long-int-long-long-long
출처 2 : https://smallpants.tistory.com/10
- float
float는 4byte 크기를 가지는 실수형 자료형이다.float는 %f 를 사용해 출력한다.float 의 중요한 점은 숫자 뒤에 f 를 붙여줘야 한다는 점이다.(3.141592f)
#include <stdio.h>
int main()
{
float f = 3.141592f; //수자 뒤에 f를 붙인다.
printf("%f", f);
}
결과
3.141592
아래 예제는 원하는 자리수를 지정하는 방법이다.
%.2f 처럼 작성해 주면 2번째 자리인 3.14가 출력된다.
만약 3번째까지 출력하고 싶다면 .3을 적어주면된다.
#include <stdio.h>
int main()
{
float f = 3.141592;
printf("%.2f\n", f);
}
결과
3.14
- double
double는 8byte 크기를 가지는 실수형 자료형이다.
double은 %lf를 사용해 출력한다.
#include <stdio.h>
int main()
{
double d = 3.141592;
printf("%lf", d);
}
결과
3.141952
아래 예제는 원하는 자리수를 지정하는 방법이다.
%.2lf 처럼 작성해 주면 2번째 자리인 3.14가 출력된다.
만약 3번째까지 출력하고 싶다면 .3을 적어주면된다.
#include <stdio.h>
int main()
{
double d = 3.141592;
printf("%.2lf\n", d);
}
결과
3.14
- float 와 double 의 유효 자리수
아래 예제는 변수 f는 소수점 10자리 까지, d는 소수점 20자리까지 출력하는 예제다.
#include <stdio.h>
int main()
{
float f = 3.1415926535897932384626;
printf("%.10f\n", f); //10자리 출력
double d = 3.1415926535897932384626;
printf("%.20lf\n", d); //20자리 출력
}
결과
3.1415927410
3.14159265358979310000
결과 값을 보면 파란색 숫자 부분부터 이상한 값이 나온다.
원래 값 : f = 3.1415926535, d = 3.14159265358979323846
출력 값 : f = 3.1415927410 d = 3.14159265358979310000
이런 문제가 발생한 이유는 float는 6자리, double은 15자리의 유효 자리수를 가지기 때문에 유효 자리수를 넘으면 쓰레기 값이 들어오게 된다.
따라서 실수형 변수를 선언 할 때는 유효 자리수를 지켜주는게 중요하다.
- 서식 지정자
우리가 위에서 printf문으로 출력하기 위해 사용했던 %d, %c, %f, %lf 를 서식 지정자(format specifier) 라고 한다.
아래 표는 각 자료형마다 사용하는 서식 지정자다.
전부 외울 필요는 없고 자주 쓰는 %d, %f, %c 정도는 외워두면 된다.
서식 지정자 | 자료형 | 출력형태 |
%d | char, short, int | 부호있는 정수 |
%ld | long | 부호있는 정수 |
%lld | long long | 부호있는 정수 |
%u | unsigned int | 부호없는 정수 |
%f | float | 부동소수점 실수 |
%lf | double, long double | 부동소수점 실수 |
%c | char, short, int | 값에 대응하는 문자 |
%s | char*(문자열) | 문자열 |
%p | void(주소값 | 포인터 주소 값 |
%o | unsigned int | 8진 정수 |
%x, %X | float, double | 16진 정수 |
- 8진수, 16진수 서식 지정자
8진수 서식지정자 : %o (영어 소문자 o임)
16진수 서식자 : %x or %X (소문자 x 사용시 출력 소문자, 대문자 X 사용시 출력 대문자)
#include <stdio.h>
int main()
{
int a = 14; //10진수
printf("10진수 = %d, 8진수 = %o, 16진수 = %x", a, a, a);
}
결과
10진수 = 14, 8진수 = 16, 16진수 = e
- 변수선언 시 주의점
변수 이름 지을 때는 주의할 점이 몇 가지 있다.
1. 특수문자 사용 불가능
int @apple; //특수 문자 @ 사용금지
2. 공백 사용 불가능
int app le; // app 과 le 사이 공백 불가능
3. 이름 처음에 숫자 사용 불가능
int 2a; // 변수 이름 처음에 숫자 불가능
int a2; // 처음에 문자오면 가능
4. 키워드 변수명으로 사용 불가능
C언어에서 이미 사용하는 키워드를 변수명으로 사용 할 수 없다.
표를 보면 익숙한 int, long, double 같은 자료형도 다 키워드다.
int auto; // 이미 사용되는 키워드이므로 불가능
auto | double | int | struct |
break | else | long | switch |
case | enum | register | typedef |
char | extern | return | union |
const | float | short | unsigned |
continue | for | signed | void |
default | goto | sizeof | volatile |
do | if | static | while |
5. 위에 조건들이 다 맞으면 변수의 이름은 알파벳, 숫자, 언더바( _ )로 구성된다.
int a_2; //가능
6. 변수명은 대소문자 구분한다.
int Data; //대소문자 구분하므로 Data와 data는 다른 변수임
int data;
7. 변수명은 한눈에 알아 볼 수 있게 의미 있는 단어를 사용해야한다.
int c = 1 + 5; //c 변수 보다는
int sum = 1 + 5 //합계를 나타내는 sum 이라고 지어주는게 좋음
- 초기화
선언 된 변수에다가 처음으로 값을 저장하는 것을 초기화라고 한다.
int a = 5; //변수 a에 5를 저장하여 초기화
- 쓰레기 값
변수를 초기화 하지 않으면 쓰레기 값이 저장된다.쓰레기 값은 아무 의미없는 임의의 값을 뜻한다.
int a; //변수를 선언만 하고 초기화 하지 않으면 쓰레기 값이 저장
- 마치며
변수와 자료형에 대해서 알아봤다.
기존 문법은 물론 함께 알고있으면 좋은 내용까지 작성했으니 꼭 직접 코드 돌려보면서 해보길 바란다.
'C 언어' 카테고리의 다른 글
[c언어 강좌] 6. 입출력 함수 (0) | 2024.10.21 |
---|---|
[c언어 강좌] 5. enum(열거형) (0) | 2024.08.16 |
[C언어 강좌] 3. main 함수란 (0) | 2024.08.11 |
[C언어 강좌] 2. visual studio 설치 및 프로젝트 생성 (0) | 2024.08.10 |
[C언어 강좌] 1. C언어 란? (0) | 2024.08.10 |