C 언어

[C언어 강좌] 4. 변수와 자료형

Let it out 2024. 8. 14. 06:02
반응형

이번에는 변수와 자료형에 대해서 다뤄 보려고 한다.
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 는 크기가 1byte0 ~ 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.1415926535d = 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; //변수를 선언만 하고 초기화 하지 않으면 쓰레기 값이 저장

 


- 마치며

변수와 자료형에 대해서 알아봤다.
기존 문법은 물론 함께 알고있으면 좋은 내용까지 작성했으니 꼭 직접 코드 돌려보면서 해보길 바란다.

 

반응형