[C언어] 상수와 기본 자료형

김민정·2024년 7월 23일
0
post-thumbnail

Chapter 05. 상수와 기본 자료형

05-1 "C언어가 제공하는 기본 자료형의 이해"

자료형이란 데이터를 표현하는 기준이다. 때문에 변수도 상수도 자료형에 근거한다.

기존에 우리는 변수를 선언할 때 int num;이라 표현했다.
이 말은 즉, '정수를 저장할건데 그 크기는 4바이트고 변수의 이름은 num으로 하겠다'라는 뜻이다.

기본 자료형의 종류와 데이터의 표현범위

자료형의 수는 데이터 표현방법의 수를 뜻한다. C언어에서 기본적으로 제공되는 자료형(기본 자료형)은 아래와 같다.

같은 정수 자료형이더라도 표현에 사용되는 바이트 크기가 클수록 표현할 수 있는 값의 범위가 넒어지고 있다. 이렇듯 다양한 자료형을 제공하는데에는 이유가 크게 2가지 있다.

  1. 데이터의 표현방식이 다르므로 최소 둘 이상의 자료형이 필요하다.
  2. 메모리 공간의 적절한 사용을 위해 다양한 크기의 자료형이 필요하다.

연산자 sizeof

sizeof 연산자를 이용하면 메모리 공간에서 소모하는 메모리의 크기를 바이트 단위로 계산해서 반환해준다.
이 연산자의 피연산자로는 변수와 상수뿐 아니라 자료형의 이름도 올 수 있다.
sizeof 연산자를 사용할 때 피연산자를 소괄호로 감싸는데 이때문에 함수로 오인하는 경우가 많다. sizeof는 연산자이다!

예제를 통해 연산 결과를 확인해보자.

#include <stdio.h>

int main()
{
	char ch = 9;
	int inum = 1052;
	double dnum = 3.1415;
	printf("변수 ch의 크기: %d \n", sizeof(ch));
	printf("변수 inum의 크기: %d \n", sizeof(inum));
	printf("변수 dnum의 크기: %d \n", sizeof(dnum));

	printf("char의 크기: %d \n", sizeof(char));
	printf("short의 크기: %d \n", sizeof(short));
	printf("int의 크기: %d \n", sizeof(int));
	printf("long의 크기: %d \n", sizeof(long));
	printf("long long의 크기: %d \n", sizeof(long long));
	printf("float의 크기: %d \n", sizeof(float));
	printf("double의 크기: %d \n", sizeof(double));
	printf("long double의 크기: %d \n\n", sizeof(long double));
	return 0;
	}

정수를 표현 및 처리하기 위한 일반적인 자료형의 선택

그럼 정수형 데이터를 처리할 때 값의 범위에 맞춰서 형을 선택하면 될까? 더 효율적일까?
상황에 따라 다르다.
예제를 통해 그 이유를 알아보자.

#include <stdio.h>

int main()
{
	char num1 = 1, num2 = 2, result1 = 0;
	short num3 = 300, num4 = 400, result2 = 0;

	printf("size of num1 & num2: %d, %d \n", sizeof(num1), sizeof(num2));
	printf("size of num3 & num4: %d, %d \n", sizeof(num3), sizeof(num4));

	printf("size of char add: %d \n", sizeof(num1 + num2));
	printf("size of short add: %d \n", sizeof(num3 + num4));
	
	result1 = num1 + num2;
	result2 = num3 + num4;
	printf("size of result1 & result2: %d, %d \n\n", sizeof(result1), sizeof(result2));
	return 0;
}

num1과 num2는 char형이기 때문에 각 데이터의 크기는 1바이트이고, 덧셈결과의 크기는 1바이트로 나올 것이다.
num3과 num4는 short형이기 때문에 각 데이터의 크기는 2바이트, 덧셈결과의 크기는 2바이트가 될 것이다.
하지만 둘 다 모두 4 바이트가 나왔다.

이는 일반적으로 CPU가 처리하기에 가장 적합한 크기의 정수 자료형을 int로 정의한다. 따라서 int형 연산의 속도가 다른 자료형의 연산속도에 비해 동일하거나 더 빠르다.
int보다 작은 크기의 데이터가 연산되면 int형 데이터로 바뀌어 (형 변환이 되어) 연산이 진행된다. 따라서 int형 덧셈결과가 반환된다.
특히 연산의 횟수가 빈번한 경우에는 저장되는 값의 크기가 작더라도 int형 변수를 선언하는 것이 좋다.

그럼 char형 변수와 short형 변수는 언제 사용하면 될까?
연산속도보다 데이터의 크기를 줄이는 것이 더 중요한 데이터에서 사용된다.

실수를 표현 및 처리하기 위한 일반적인 자료형의 선택

실수 자료형의 선택에 있어서 가장 중요한 요소는 정밀도다.
정밀도란? 오차가 발생하지 않는 소수점 이하의 자릿수를 말한다. 이러한 오차는 데이터 표현에 사용되는 바이트 수가 커지면 줄어든다.

그럼 실수에서 일반적으로 사용되는 실수 자료형은 뭘까? double이다.

예제를 통해 실수 자료형에 대해 알아보자.

#include <stdio.h>

int main()
{
	double rad;
	double area;
	printf("원의 반지름 입력: ");
	scanf_s("%lf", &rad);	// double형 데이터를 입력 받을 때는 서식문자 `%lf`를 사용

	area = rad * rad * 3.1415;
	printf("원의 넓이: %f \n\n", area);	// double형 데이터를 출력할 때는 서식문자 `%f`를 사용
	return 0;
}

양의 정수만 표현하는 방법: unsinged

정수 자료형의 이름에 한에서 unsigned 선언을 추가하면 0 이상의 값만 표현하는 자료형이 되어 양의 정수 방향으로 2배 넒어지게 된다. MSB 부분도 데이터의 크기를 표현하는데 사용되기 때문에 2배로 느는 것이다!
signed int = int 이기 때문에 보통 singed를 생략하는 것이다.
반면에 char형은 좀 예외일 수 있다. unsigned char로 처리하는 컴파일러도 존재하기 때문에 음의 정수를 저장하는 경우에 signed 선언을 추가하기도 한다.


05-2 "문자의 표현방식과 문자를 위한 자료형"

컴퓨터는 숫자를 이용해 문자를 표현한다.

ASCII(아스키) 코드

숫자를 이용해 문자를 표현하려면 숫자를 문자에 연결(mapping) 시켜야한다.
아스키 코드는 알파벳과 일부 특수문자를 포함하여 총 128개의 문자로 이뤄져 있다.

프로그램상에서의 문자표현에는 작은 따옴표가 사용된다. 이렇게 표현된 문자는 컴파일에 의해 아스키 코드 표에서 보듯 숫자로 변환된다.

예제를 통해 문자 변환에 대해 알아보자.

#include <stdio.h>

int main(void)
{
	char ch1 = 'A', ch2 = 65;
	int ch3 = 'Z', ch4 = 90;

	printf("%c %d \n", ch1, ch1);	// %c는 문자의 형태로 데이터를 출력
	printf("%c %d \n", ch2, ch2);
	printf("%c %d \n", ch3, ch3);
	printf("%c %d \n\n", ch4, ch4);
	return 0;
}

아스키 코드 표에 따라 정수는 출력의 방법에 따라 문자로든 숫자로든 출력이 가능하다.
아스키 코드 값은 0~127이기 때문에 char형 변수로 충분히 저장 가능하다.


05-3 "상수에 대한 이해"

상수는 변수의 상대적인 개념으로 이름이 있는 상수와 이름이 없는 상수로 크게 나눌 수 있다.
상수 역시 int, double과 같은 자료형을 근거로 표현이 된다.

Literal(리터럴) 상수: 이름이 없는 상수

상수란, 변경이 불가능한 데이터를 뜻한다.

예를 들어

int main(void)
{
	int num = 30 + 40;
    ...
}

이런 코드가 있다면 여기서 상수는 30과 40을 가리킨다. 메모리 공간에 저장되는 변수 num과 달리 상수 30과 40은 메모리 공간에 저장되지 않는다.

리터럴 상수의 자료형

메모리 상에 저장되는 모든 데이터는 자료형이 결정되어야 한다.
예를 들어

int main(void)
{
	int num = 5;
    double dnum = 7.15;
}

int형으로 표현 가능한 정수형 상수는 int형으로 메모리 공간에 저장된다.
double형으로 표현 가능한 실수형 상수는 double형으로 저장된다.
아스키 코드도 char형으로 동일한 방법을 통해 저장된다.

예제를 통해 확인해보자.

#include <stdio.h>

int main()
{
	printf("literal int size: %d \n", sizeof(7));
	printf("literal double size: %d \n", sizeof(7.14));
	printf("literal char size: %d \n", sizeof('A'));	
	return 0;
}

sizeof 연산자를 통해 리터럴 상수의 크기를 확인해볼 수 있다. 문자형 상수의 크기가 int형인 4 바이트로 표현됨도 확인해볼 수 있다.

접미사를 이용한 다양한 상수의 표현

int와 double말고 다른 자료형으로 상수를 표현하려면 어떻게 하면 될까?
해당 자료형을 의미하는 접미사를 붙여주면 된다!
예시를 통해 알아보자.

#include <stdio.h>

int main()
{
	float num1 = 5.789;
	float num2 = 3.24 + 5.12;

	printf("%f, %f\n", num1, num2);
	float fnum1 = 5.789f;	// float형 상수를 float형 변수에 저장.
	float fnum2 = 3.24F + 5.12F;	//대문자 소문자 구별 X

	printf("%f, %f\n", fnum1, fnum2);
	return 0;
}

다만 컴파일 하면 아래와 같은 경고 메시지를 확인할 수 있다.

이건 결과 창

8바이트 크기의 double형 상수를 4바이트 크기의 float형으로 나타내려다보니 발생하는 것이다. float형 상수를 float형 변수에 저장하려면 예시와 같이 접미사를 상수 뒤에 붙여주면 된다.

위 접미사들은 대소문자를 구분하지 않으니 상황에 맞게 잘 사용해주면된다.

Symbolic(심볼릭)상수: const 상수

심볼릭 상수는 변수와 마찬가지로 이름을 지니는 상수다.
심볼릭 상수를 표현하는 방법에는 두 가지가 있다.
1. const 키워드를 사용
2. 매크로를 이용

매크로를 이용하는 방법은 추후 chapter 26에서 다룰 예정이다.

const 키워드를 이용해서 심볼릭 상수를 만드는 방법은 아래 예시와 같다.

int main(void)
{
	const int MAX = 100;	// MAX는 상수, 따라서 값의 변경 불가.
    const double PI = 3.14;	// PI는 상수, 따라서 값의 변경 불가.
	...
}

심볼릭 상수도 상수의 일종이므로 일단 초기화되면 그 값을 변경시킬 수 없고, 선언과 초기화를 분리시킬 수도 없다.
상수의 이름은 모두 대문자로 표시하고, 둘 이상의 단어로 연결할 때에는 언더바(_)를 이용해 두 단어를 구분하는 것이 관례다.


05-4 "자료형의 변환"

자료형의 변환이란? char형으로 표현되어 있는 데이터의 표현방식을 int형으로 바꾸거나 int형으로 표현되어 있는 데이터의 표현방식을 double형으로 바꾸는 것이다.
즉, 데이터의 표현방식을 바꾸는 것이다.
자료형의 변환은 크게 두 가지로 나뉜다.
1. 자동 형 변환(묵시적 형 변환)
2. 강제 형 변환(명시적 형 변환)

자동 형 변환: 묵시적 형 변환

1. 대입 연사의 전달과정에서 발생

자동 형 변환은 대입 연산의 전달 과정에서 대입 연산자의 왼편과 오른편에 존재하는 두 피연산자의 자료형이 일치하지 않으면 왼편에 있는 피연산자를 대상으로 형 변환이 자동으로 일어난다.

예를 들어, double num1 = 234;라면 int형 정수를 double형으로 맞춰 자동 형 변환이 되어 num1에 저장된다.

그렇다면 실수형 데이터를 정수형 데이터로 변환하면 어떨까? 소수점 이하의 값이 버려지는 소수부의 손실이 발생하게 된다.
int형 (4byte)을 char형(1byte)로 변환하면 어떨까? 예를 들어 129는 00000000 00000000 00000000 10000001로 나타낼 수 있고 변환되면서 10000001이 되어 상위 바이트의 손실이 발생하며 부호가 바뀔 수도 있어 주의해야한다.

따라서, 데이터의 표현범위가 보다 넓은 자료형으로의 형 변환은 그 과정에서 데이터의 손실이 발생하지 않지만, 데이터의 표현범위가 보다 좁은 자료형으로의 형 변환은 데이터의 손실이 발생할 수 있다.

예제를 통해 자동 형 변환을 확인해보자.

#include <stdio.h>

int main()
{
	int num1 = 3;
	double num2 = 2.2;

	double result1 = num1 / num2;		//int형을 double형으로 변환
	double result2 = num1 / (int)num2;	//double형을 int형으로 변환

	printf("result1 : %f \n", result1);
	printf("result2 : %f \n\n", result2);

	double num3 = 17.23;
	int num4 = (int)num3;	//double형을 int형으로 변환

	printf("num1 : %f \n", num3);
	printf("num2 : %d \n\n", num4);

	double Num1 = 245;
	int Num2 = 3.1415;
	int Num3 = 129;
	char ch = Num3;

	printf("정수 245를 실수로: %f \n", Num1);
	printf("실수 3.1415룰 정수로: %d \n", Num2);
	printf("큰 정수129를 작은 정수로: %d \n\n", ch);	
	// 여기서 char형의 수는 128이 끝이기 때문에 상위 바이트 손실로 음수로 부호 바뀜.
	return 0;
}

2. 정수의 승격(Integral Promotion)에 의한 변환

앞서 애기했듯 CPU에서 처리하기에 가장 적합한 크기의 정수형은 int다. 따라서 int보다 작은 크기의 정수형 데이터는 int형으로 변환되어 연산이 진행된다.
이러한 형태의 형 변환을 가리켜 정수의 승격(Integral Promotion)이라 한다.

3. 피연산자의 자료형 불일치로 발생

사칙연산과 같은 기본적인 산술연산에서 피연산자의 자료형이 일치하지 않을 시 일치를 목적으로 자동 형 변환이 일어난다. 이때, 일어나는 자동 형 변환은 데이터의 손실을 최소화하는 방향으로 진행된다.

char형과 short형은 연산의 경우 int형으로 정수의 승격이 적용되기 때문에 위 규칙에서 생략되었다. 그리고 byte가 크다고 무조건 우선순위가 앞서는 것이 아닌 정수 자료형보다 실수 자료형이 무조건 앞서는 형태로 정의되어 있다.

강제 형 변환: 명시적 형 변환

명시적 형 변환이란, 형 변환 연산자를 이용해 강제로 형 변환을 명령하는 것을 말한다.
예제로 확인해보자.

#include <stdio.h>

int main()
{
	int Num4 = 3, Num5 = 4;
	double divResult;
	double DivResult;
	divResult = Num4 / Num5;
	DivResult = (double)Num4 / Num5;
	printf("나눗셈 결과: %f \n", divResult);	// 결과값 0.000000
	printf("나눗셈 결과: %f \n\n", DivResult);	// 결과값 0.750000
	return 0;
}

연산 결과(divResult)의 자료형은 피연산자의 자료형과 일치한다.
DivResult와 같이 형 변환을 위해 사용되는 소괄호를 가리켜 형 변환 연산자(type casting operator)라 하고 연산의 결과로는 변환된 값이 반환된다.


<Review>

드디어 자료형까지 배워봤다!
python을 6개월 사용하다보니 자료형이 이렇게 많았다는 걸 까먹었었는데 다시 배워보니 너무 재밌다 ㅎㅎㅎ
사실 아직 잘 알지 못하고 잘 하진 못하지만 새로운 걸 배우는 건 언제나 신기하고 세상엔 똑똑한 사람이 정말 많은거 같다 ㅎㅎ 오늘은 이만 여기서 끝!

profile
백엔드 코린이😁

0개의 댓글

관련 채용 정보