본문 바로가기
C언어

C언어 타입

by godfeeling 2020. 7. 4.

변수(variable)

변수(variable)란 데이터(data)를 저장하기 위해 프로그램에 의해 이름을 할당받은 메모리 공간을 의미합니다.

 

, 변수란 데이터(data)를 저장할 수 있는 메모리 공간을 의미하며, 이렇게 저장된 값은 변경될 수 있습니다.

 

 

 

C언어에서 숫자 표현에 관련된 변수는 정수형 변수와 실수형 변수로 구분할 수 있습니다.

 

또다시 정수형 변수는 char, int, long형 변수로, 실수형 변수는 float, double형 변수로 나눌 수 있습니다.

 

 

 

또한, 데이터가 저장된 메모리의 주소를 저장하고 처리하는 포인터 변수가 있습니다.

 

관련된 정보를 한 번에 묶어서 처리하는 사용자 정의 구조체 변수도 있습니다.

 

변수의 이름 생성 규칙

C언어에서는 변수의 이름을 비교적 자유롭게 지을 수 있습니다.

 

하지만 변수의 이름은 해당 변수에 저장될 데이터의 의미를 잘 나타내도록 짓는 것이 가장 좋습니다.

 

 

 

C언어에서 변수의 이름을 생성할 때에 반드시 지켜야 하는 규칙은 다음과 같습니다.

 

 

 

1. 변수의 이름은 영문자(대소문자), 숫자, 언더스코어(_)로만 구성됩니다.

 

2. 변수의 이름은 숫자로 시작될 수 없습니다.

 

3. 변수의 이름 사이에는 공백을 포함할 수 없습니다.

 

4. 변수의 이름으로 C언어에서 미리 정의된 키워드(keyword)는 사용할 수 없습니다.

 

 

 

다음 표는 변수의 이름을 생성할 때에 지겨야하는 규칙의 예시입니다.

 

변수의 이름이 올바른 경우

변수의 이름이 잘못된 경우

잘못된 이유

int tcp

                       int t!cp*

변수 이름이 영문자,숫자, _ 외에 특수문자 사용하였음

int school

                     int 6school

변수 이름이 숫자로 시작하였음

int tcpschool

                   int tcp school

변수 이름 tcpschool 사이에 공백이 있음

int int

                         int int

변수 이름에 int라는 키워드를 사용하였음

 

 

C언어에서는 변수의 이름에 대소문자를 구분하므로 이 점에 주의해야 합니다.

ex) int tcp int Tcp 는 같은 변수가 아닙니다.

 

다음은 C언어에서 사용되는 키워드(Keyword)들입니다.

키워드(Keyword)는 고유한 의미를 가지는 예약어입니다. C언어에는 32개의 키워드가 있으며, 이러한 키워드들은 미국표준협회 ANSI에서 지정한 키워드들 입니다. 아래의 키워드들은 위의 예시처럼 변수의 이름으로 사용할 수 없습니다.

 

 

 auto

 beak

 case

 char

 const

 continue

 default

 do

 double

 else

 enum

 extern

 float

 for

 goto

 if

 int

 long

 register

 return

 short

 signed  

 sizeof

 static

struct

 switch

 typedef

 union

 unsigend

 void 

 volatile

 while

 

 

 

 

비트(bit)와 바이트(byte)

컴퓨터는 모든 데이터를 2진수로 표현하고 처리합니다.

 

비트(bit)란 컴퓨터가 데이터를 처리하기 위해 사용하는 데이터의 최소 단위입니다.

 

이러한 비트에는 2진수의 값(01)을 단 하나만 저장할 수 있습니다.

 

바이트(byte)란 위와 같은 비트가 8개 모여서 구성되며, 한 문자를 표현할 수 있는 최소 단위입니다.

 

변수와 메모리 구조

변수는 기본적으로 메모리의 주소(address)를 기억하는 역할을 합니다.

 

메모리 주소란 물리적인 메모리 공간을 서로 구분하기 위해 사용되는 일종의 식별자입니다.

 

, 메모리 주소란 메모리 공간에서의 정확한 위치를 식별하기 위한 고유 주소를 의미합니다.

 

 

 

변수를 참조할 때는 메모리의 주소를 참조하는 것이 아닌, 해당 주소에 저장된 데이터를 참조하게 됩니다.

 

따라서 변수는 데이터가 저장된 메모리의 주소뿐만 아니라, 저장된 데이터의 길이와 형태에 관한 정보도 같이 기억해야 합니다.

하나의 메모리 공간에는 8개의 비트로 이루어진 1바이트의 데이터가 저장됩니다.

 

따라서 메모리의 주소 또한 1바이트씩 증가되며, 낮은 주소부터 차례대로 데이터가 저장됩니다.

 

변수의 길이가 총 4개의 메모리 공간을 포함하면, 해당 변수에는 4바이트의 데이터가 저장되어 있습니다.

 

이때 변수의 이름은 첫 번째 메모리 주소인 0x10만을 가리키게 됩니다.

 

따라서 변수의 길이가 4이며, 변수가 어떤 형태로 구성되는지도 알아야만 해당 변수에서 데이터를 올바르게 참조할 수 있습니다.

 

변수의 선언

C언어에서는 변수를 사용하기 전에 반드시 먼저 해당 변수를 저장하기 위한 메모리 공간을 할당받아야 합니다.

 

이렇게 해당 변수만을 위한 메모리 공간을 할당받는 행위를 변수의 선언이라고 부릅니다.

 

만약 선언되지 않은 변수를 사용하려고 하면, C 컴파일러는 오류를 발생시킵니다.

 

 

 

C언어에서 변수를 선언하는 방법은 다음과 같이 두 가지 방법이 있습니다.

 

 

 

1. 변수의 선언만 하는 방법

 

2. 변수의 선언과 동시에 초기화하는 방법

 

변수의 선언만 하는 방법

이 방법은 먼저 변수를 선언하여 메모리 공간만을 할당받고, 나중에 변수를 초기화하는 방법입니다.

 

 

 

C언어에서 변수를 선언하는 방법은 다음과 같습니다.

 

문법

타입 변수이름;

 

예제

int num;

 

...

 

num = 20;

 

 

 

위의 예제처럼 정수를 저장하기 위한 메모리 공간을 할당받으면, 반드시 해당 타입의 데이터만을 저장해야 합니다.

 

그렇지 않고 다른 타입의 데이터를 저장할 경우에는 저장된 데이터에 변형 및 손실이 일어날 수도 있습니다.

 

 

 

변수의 초기화란 해당 변수를 사용할 수 있도록 초기값을 설정하는 행위입니다.

 

초기화되지 않은 변수에는 아무런 의미 없는 값인 쓰레깃값만이 들어가 있습니다.

 

예제

int num;

 

printf("%d", num);

 

 

 

위의 예제에서 변수 num은 선언만 하고 아직 초기화되지 않았습니다.

 

하지만 printf() 함수에서 변수 num을 사용하여 해당 변수에 저장된 값을 출력하려고 하고 있습니다.

 

 

 

이와 같은 경우에 C 컴파일러는 오류를 발생시키지는 않겠지만, 프로그램은 사용자가 의도하지 않은 결과를 출력할 것입니다.

 

따라서 C언어에서는 초기화되지 않은 변수는 절대로 사용해서는 안됩니다.

 

변수의 선언과 동시에 초기화하는 방법

C언어에서 변수는 선언과 동시에 그 값을 초기화할 수 있습니다.

 

또한, 선언하고자 하는 변수들의 타입만 같다면 여러 변수를 동시에 선언할 수도 있습니다.

 

문법

1. 타입 변수이름[, 변수이름];

 

2. 타입 변수이름 = 초깃값[, 변수이름 = 초깃값];

 

예제

 

 

int num01, num02;

 

double num03 = 1.23, num04 = 4.56;

 

 

선언하고자 하는 변수의 타입이 서로 다르면 동시에 선언할 수 없습니다.

 

 

상수(constant)

상수(constant)란 변수와 마찬가지로 데이터를 저장할 수 있는 메모리 공간을 의미합니다.

 

하지만 상수가 변수와 다른 점은 프로그램이 실행되는 동안 상수에 저장된 데이터는 변경할 수 없다는 점입니다.

 

 

 

이러한 상수는 표현 방식에 따라 다음과 같이 나눌 수 있습니다.

 

 

 

1. 리터럴 상수(literal constant)

 

2. 심볼릭 상수(symbolic constant)

 

리터럴 상수(literal constant)

리터럴 상수(literal constant)는 변수와는 달리 데이터가 저장된 메모리 공간을 가리키는 이름을 가지고 있지 않습니다.

 

C언어에서는 적절한 메모리 공간을 할당받기 위하여, 기본적으로 변수든 상수든 타입을 가지게 됩니다.

 

 

 

리터럴 상수는 타입에 따라 정수형 리터럴 상수, 실수형 리터럴 상수, 문자형 리터럴 상수 등으로 구분할 수 있습니다.

 

 

 

1. 정수형 리터럴 상수는 123, -456과 같이 아라비아 숫자와 부호로 직접 표현됩니다.

 

2. 실수형 리터럴 상수는 3.14, -45.6과 같이 소수 부분을 가지는 아라비아 숫자로 표현됩니다.

 

3. 문자형 리터럴 상수는 'a', 'Z'와 같이 따옴표('')로 감싸진 문자로 표현됩니다.

 

 

 

예제

123 // 정수형 리터럴 상수

 

3.14 // 실수형 리터럴 상수

 

'a' // 문자형 리터럴 상수

 

심볼릭 상수(symbolic constant)

심볼릭 상수는 변수와 마찬가지로 이름을 가지고 있는 상수입니다.

 

이러한 심볼릭 상수는 반드시 선언과 동시에 초기화되어야 합니다.

 

심볼릭 상수는 const 키워드를 사용하거나, 매크로를 이용하여 선언할 수 있습니다.

 

 

 

예제

const int MAX = 10; // const 키워드를 이용한 심볼릭 상수

 

#define MAX 10; // #define 선행처리 지시자를 이용한 매크로 심볼릭 상수

 

 

기본 타입

C언어에서 타입(data type)이란 해당 데이터가 메모리에 어떻게 저장되고, 프로그램에서 어떻게 처리되어야 하는지를 명시적으로 알려주는 역할을 합니다.

 

따라서 C언어는 여러 형태의 타입을 미리 작성하여 제공하고 있는데, 이것을 기본 타입이라고 합니다.

 

이러한 기본 타입은 크게 정수형, 실수형, 그리고 문자형 타입으로 나눌 수 있습니다.

 

정수형 타입

C언어에서 정수란 부호를 가지고 있고, 소수 부분이 없는 수를 의미합니다.

 

 

 

정수형 데이터에 unsigned 키워드를 추가하면, 부호를 나타내는 최상위 비트(MSB, Most Significant Bit)까지도 크기를 나타내는 데 사용할 수 있습니다.

 

이러한 unsigned 정수는 음수를 표현할 수는 없게 되지만, 0을 포함한 양의 정수는 두 배 더 많이 표현할 수 있게 됩니다.

 

음의 정수까지도 표현할 수 있는 signed 키워드는 모든 타입에서 기본적으로 생략하여 사용할 수 있습니다.

 

최상위 비트(MSB, Most Significant Bit)1바이트를 구성하는 8개의 비트 중 최고값을 갖는 비트를 의미합니다.

 

다음 표는 각각의 정수 타입에 따른 메모리의 크기 및 데이터의 표현 범위를 나타냅니다.

 

정수형 타입

할당되는 메모리의 크기

데이터의 표현 범위

(signed) short

2 바이트

- 32,768 ~ 32,767

unsigned short

2 바이트

- 0 ~ 65,535

(signed) int

4 바이트

- 2,147,483,648 ~ 2,147,483,647

unsigned int

4 바이트

- 0 ~ 4,294,967,296

(signed) long

4 바이트

- 2,147,483,648 ~ 2,147,483,647

unsigned long

4 바이트

- 0 ~ 4,294,967,296

 

 

정수형 데이터의 타입을 결정할 때에는 반드시 자신이 사용하고자 하는 데이터의 최대 크기를 고려해야 합니다.

 

해당 타입이 표현할 수 있는 범위를 벗어난 데이터를 저장하면, 오버플로우가 발생해 전혀 다른 값이 저장될 수 있기 때문입니다.

 

 

 

오버플로우(overflow)란 해당 타입이 표현할 수 있는 최대 범위보다 큰 수를 저장할 때 발생하는 현상을 가리킵니다.

 

오버플로우가 발생하면 최상위 비트(MSB)를 벗어난 데이터가 인접 비트를 덮어쓰므로, 잘못된 결과를 얻을 수 있습니다.

 

또한, 언더플로우(underflow)란 해당 타입이 표현할 수 있는 최소 범위보다 작은 수를 저장할 때 발생하는 현상을 가리킵니다.

 

 

 

다음 예제는 int형 변수에 해당 타입이 저장할 수 있는 최댓값과 그 최댓값을 넘는 숫자를 대입하는 예제입니다.

 

예제

int num = 2147483647; // int형 타입이 저장할 수 있는 최댓값인 231 - 1

 

printf("변수 num에 저장된 값은 %d입니다.\n", num);

 

 

 

num = 2147483648; // int형 타입이 저장할 수 없는 숫자인 231

 

printf("변수 num에 저장된 값은 %d입니다.\n", num);

 

위의 두 번째 실행 결과를 살펴보면, 변수 num에 양수를 대입했지만 음수로 저장된 것을 확인할 수 있습니다.

 

이처럼 오버플로우가 발생하면 전혀 예상치 못한 결과를 얻을 수 있으므로, 데이터를 저장할 때는 언제나 해당 데이터 타입의 최대 크기까지 고려해야 합니다.

 

컴퓨터는 내부적으로 정수형 중에서도 int형의 데이터를 가장 빠르게 처리합니다.

 

따라서 정수형 데이터는 보편적으로 크기에 상관없이 int형을 가장 많이 사용합니다.

 

int형은 운영체제의 환경에 따라 다릅니다.

 

16bit라면 2바이트, 32bit라면 4바이트, 64bit이상부터 4바이트입니다.

 

실수형 타입

C언어에서 실수란 소수부나 지수가 있는 수를 가리키며, 정수보다 훨씬 더 넓은 표현 범위를 가집니다.

 

하지만 컴퓨터에서 실수를 표현하는 방식은 반드시 오차가 발생하는 기술적 한계를 지닙니다.

 

이러한 실수형 데이터의 오차는 C언어뿐만 아니라 모든 프로그래밍 언어에서 발생하는 공통된 문제입니다.

 

실수형 타입

할당되는 메모리의 크기

데이터의 표현 범위

float

4 바이트

(3.4 X 10-38) ~ (3.4 X 1038)

double

8 바이트

(1.7 X 10-308) ~ (1.7 X 10308)

long double

double형과 동일함.

double형과 동일함.

 

다음 예제는 소수점을 16자리 가지는 실수를 float형과 double형 변수에 각각 대입하는 예제입니다.

 

예제

float num01 = 3.1415926535897932; // float 타입의 유효 자릿수는 소수점 6자리

 

printf("변수 pi에 저장된 값은 %.20f입니다.\n", num01);

 

 

 

double num02 = 3.1415926535897932; // double 타입의 유효 자릿수는 소수점 16자리

 

printf("변수 pi에 저장된 값은 %.20f입니다.\n", num02);

 

위의 예제에서 변수 num01에는 소수점 6자리까지만 정확한 값이 저장되어 있고, 소수점 7자리부터는 틀린 값이 저장되어 있습니다.

 

또한, 변수 num02에는 소수점 15자리까지만 정확한 값이 저장되어 있고, 소수점 16자리부터는 틀린 값이 저장되어 있는 것을 확인할 수 있습니다.

 

 

 

이처럼 실수형 데이터의 타입을 결정할 때는 표현 범위 이외에도 유효 자릿수를 반드시 고려해야 합니다.

 

실수형 타입

지수의 길이

가수의 길이

유효 자릿수

float

8 비트

23 비트

소수 부분 6자리까지 오차없이 표현할 수 있음.

double

11 비트

52 비트

소수 부분 15자리까지 오차없이 표현할 수 있음.

 

과거에는 실수를 표현할 때 float형을 많이 사용했지만, 하드웨어의 발달로 인한 메모리 공간의 증가로 현재에는 double형을 가장 많이 사용합니다.

 

문자형 타입

C언어에서 문자형 데이터란 문자 하나를 표현할 수 있는 타입을 의미합니다.

 

컴퓨터는 2진수밖에 인식하지 못하므로, 문자도 숫자로 표현해야 컴퓨터가 인식할 수 있습니다.

 

따라서 어떤 문자를 어떤 숫자에 대응시킬 것인가에 대한 약속이 필요해집니다.

 

 

 

이러한 약속 중에서 가장 많이 사용되는 것이 바로 아스키코드(ASCII)입니다.

 

아스키코드(ASCII)는 영문 대소문자를 사용하는 7비트의 문자 인코딩 방식입니다.

 

아스키코드는 문자를 7비트로 표현하므로, 128개의 문자를 표현할 수 있습니다.

 

 

 

아스키코드의 구성은 다음과 같습니다.

 

 

 

- 출력할 수 없는 33개의 문자

 

- 출력할 수 있는 52개의 영문 대소문자, 10개의 숫자, 32개의 특수 문자와 1개의 공백 문자

 

 

문자형 타입

할당되는 메모리의 크기

데이터의 표현 범위

(signed) char

1 바이트

27 ~ 2-7

unsigned char

2 바이트

0 ~ 2-8

 

 

다음 예제는 char형 변수에 저장된 문자를 여러 서식 지정자를 사용하여 출력하는 예제입니다.

 

예제

char ch = 'a';

 

printf("변수 ch에 저장된 값은 %c입니다.\n", ch);

 

printf("변수 ch에 저장된 값은 %d입니다.\n", ch);

 

위의 예제에서 서식 지정자 '%c'를 사용하여 출력한 결과는 제대로 문자 'a'가 출력됩니다.

 

하지만 서식 지정자 '%d'를 사용하여 출력한 결과는 97이라는 숫자로 출력됩니다.

 

, 이것은 문자가 C++ 내부적으로는 아스키코드에 해당하는 숫자로 저장되어 있음을 보여줍니다.

 

 

 

타입 변환(type conversion)

C언어에서 다른 타입끼리의 연산은 우선 피연산자들을 모두 같은 타입으로 만든 후에 수행됩니다.

 

이처럼 하나의 타입을 다른 타입으로 바꾸는 행위를 타입 변환(type conversion)이라고 합니다.

 

 

 

표현 범위가 좁은 타입에서 표현 범위가 더 넓은 타입으로의 타입 변환은 큰 문제가 되지 않습니다.

 

하지만 반대의 경우인 표현 범위가 좁은 타입으로의 타입 변환에서는 데이터의 손실이 발생합니다.

 

 

 

타입 변환은 크게 다음과 같이 두 가지 방식으로 나눌 수 있습니다.

 

 

 

1. 묵시적 타입 변환(자동 타입 변환)

 

2. 명시적 타입 변환(강제 타입 변환)

 

묵시적 타입 변환(자동 타입 변환, implicit type conversion)

묵시적 타입 변환은 대입 연산이나 산술 연산에서 C 컴파일러가 자동으로 실행해주는 타입 변환을 가리킵니다.

 

C언어에서는 대입 연산 시 연산자의 오른쪽에 존재하는 데이터의 타입이 연산자의 왼쪽에 존재하는 데이터의 타입으로 묵시적 타입 변환이 진행됩니다.

 

또한, 산술 연산에서는 데이터의 손실이 최소화되는 방향으로 묵시적 타입 변환이 진행됩니다.

 

 

 

다음 예제는 대입 연산에서 일어나는 묵시적 타입 변환을 보여줍니다.

 

예제

char ch = 200;

 

int num01 = 3.14;

 

double num02 = 5;

 

 

 

printf(" ch에 저장된 값은 %d입니다.\n", ch);

 

printf("num01에 저장된 값은 %d입니다.\n", num01);

 

printf("num02에 저장된 값은 %f입니다.\n", num02);

 

위의 예제에서는 char형 변수에 char형 변수가 표현할 수 있는 범위를 넘는 데이터를 저장합니다.

 

따라서 전달된 데이터의 상위 비트가 자동으로 삭제되어 데이터의 손실이 발생합니다.

 

또한, int형 변수에 실수를 저장했기 때문에 소수 부분이 자동으로 삭제되어 데이터의 손실이 발생합니다.

 

하지만 double형 변수에 int형 데이터를 저장하는 것은 데이터가 double형으로 자동 타입 변환되지만, 데이터의 손실은 발생하지 않습니다.

 

 

 

다음 예제는 산술 연산에서 일어나는 묵시적 타입 변환을 보여줍니다.

 

예제

double result01 = 5 + 3.14;

 

double result02 = 5.0f + 3.14;

 

 

 

printf("result01에 저장된 값은 %f입니다.\n", result01);

 

printf("result02에 저장된 값은 %f입니다.\n", result02);

 

 

위의 예제에서 첫 번째 연산은 int형 데이터와 double형 데이터의 산술 연산입니다.

 

따라서 데이터의 손실이 최소화되도록 int형 데이터가 double형 데이터로 자동 타입 변환됩니다.

 

두 번째 연산은 float형 데이터와 double형 데이터의 산술 연산입니다.

 

위와 마찬가지로 데이터의 손실이 최소화되도록 float형 데이터가 double형 데이터로 자동 타입 변환됩니다.

 

 

 

이렇게 컴파일러가 자동으로 수행하는 타입 변환은 언제나 데이터의 손실이 최소화되는 방향으로 이루어집니다.

 

따라서 C 컴파일러는 다음과 같은 순서대로 자동 타입 변환을 수행하게 됩니다.

 

 

 

char short int long float double long double

 

명시적 타입 변환(강제 타입 변환, explicit type conversion)

명시적 타입 변환은 사용자가 타입 캐스트(type cast) 연산자를 사용하여 강제적으로 수행하는 타입 변환을 가리킵니다.

 

변환하고자 하는 데이터의 앞에 괄호(())를 추가하고, 그 안에 변환할 타입을 적으면 됩니다.

 

C언어에서는 이 괄호(())를 타입 캐스트(type cast) 연산자라고 합니다.

 

 

 

다음 예제는 명시적 타입 변환을 보여주는 예제입니다.

 

예제

int num01 = 1;

 

int num02 = 4;

 

 

 

double result01 = num01 / num02;

 

double result02 = (double)num01 / num02;

 

 

 

printf("result01에 저장된 값은 %f입니다.\n", result01);

 

printf("result02에 저장된 값은 %f입니다.\n", result02);

 

 

위의 예제에서 첫 번째 연산의 결괏값은 0.000000으로 출력됩니다.

 

그 이유는 산술 연산에 대한 결괏값의 타입은 피연산자의 타입과 언제나 일치하기 때문입니다.

 

int형 데이터끼리의 산술 연산에 대한 결괏값은 언제나 int형 데이터로 나옵니다.

 

따라서 두 번째 연산에서처럼 하나의 피연산자를 명시적으로 double형으로 지정해야만 정확한 결괏값을 얻을 수 있습니다.

'C언어' 카테고리의 다른 글

C언어 배열  (0) 2020.07.05
C언어 함수  (0) 2020.07.04
C언어 제어문  (0) 2020.07.04
C언어 연산자  (0) 2020.07.04
C언어 기초  (0) 2020.07.04

댓글