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가 된거다.

OSApplication Bit (binary)long size
Windwos (x86-64)32 bit4 byte
64 bit4 byte
OS X (x86-64)32 bit4 byte
64 bit8 byte
Linux (x86-64)32 bit4 byte
64 bit8 byte
Aix (PowerPC)32 bit4 byte
64 bit8 byte
HP-UX (IA-64)32 bit4 byte
64 bit8 byte
Solaris (Sparc)32 bit4 byte
64 bit8 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 정도는 외워두면 된다.

서식 지정자자료형출력형태
%dchar, short, int부호있는 정수
%ldlong부호있는 정수
%lldlong long부호있는 정수
%uunsigned int부호없는 정수
%ffloat부동소수점 실수
%lfdouble, long double부동소수점 실수
%cchar, short, int값에 대응하는 문자
%schar*(문자열)문자열
%pvoid(주소값포인터 주소 값
%ounsigned int8진 정수
%x, %Xfloat, double16진 정수

 


- 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; // 이미 사용되는 키워드이므로 불가능
autodoubleintstruct
breakelselongswitch
caseenumregistertypedef
charexternreturnunion
constfloatshortunsigned
continueforsignedvoid
defaultgotosizeofvolatile
doifstaticwhile


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; //변수를 선언만 하고 초기화 하지 않으면 쓰레기 값이 저장

 


- 마치며

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

 

반응형