Language/C

[C] C언어 타입 - 변수, 상수, 기본 타입, 타입 변환

재은초 2026. 6. 4. 01:41
728x90
반응형

변수(variable)란?

  • 변수(variable)란 데이터(data)를 저장하기 위해 프로그램에 의해 이름을 할당받은 메모리 공간을 의미합니다.
  • C언어에서는 데이터가 저장된 메모리의 주소를 저장하고 처리하는 포인터 변수가 있다.
  • 또한 관련된 정보를 한 번에 묶어서 처리하는 사용자 정의 구조체 변수도 있다.

 

변수의 이름 생성 규칙

  • 변수의 이름은 영문자(대소문자), 숫자, 언더스코어(_)로만 구성된다.
  • 변수의 이름은 숫자로 시작될 수 없다.
  • 변수의 이름 사이에는 공백을 포함할 수 없다.
  • 변수의 이름으로 C언어에서 미리 정의된 키워드(keyword)는 사용할 수 없다.

https://www.tcpschool.com/c/c_datatype_variable

  • 변수의 이름에 대소문자를 구분하므로 이 점에 주의해야 한다.

 

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

  • 컴퓨터는 모든 데이터를 2진수로 표현하고 처리한다.
  • 비트(bit)란 컴퓨터가 데이터를 처리하기 위해 사용하는 데이터의 최소 단위다. 이러한 비트에는 2진수의 값(0과 1)을 단 하나만 저장할 수 있다.
  • 바이트(byte)란 위와 같은 비트가 8개 모여서 구성되며, 한 문자를 표현할 수 있는 최소 단위다.

 

변수와 메모리 구조

  • 변수는 기본적으로 메모리의 주소(address)를 기억하는 역할을 한다. 메모리 주소란 물리적인 메모리 공간을 서로 구분하기 위해 사용되는 일종의 식별자다. 즉, 메모리 주소란 메모리 공간에서의 정확한 위치를 식별하기 위한 고유 주소를 의미한다.
  • 변수를 참조할 때는 메모리의 주소를 참조하는 것이 아닌, 해당 주소에 저장된 데이터를 참조한다. 따라서 변수는 데이터가 저장된 메모리의 주소뿐만 아니라, 저장된 데이터의 길이와 형태에 관한 정보도 같이 기억해야 한다.

https://www.tcpschool.com/c/c_datatype_variable

  • 위의 그림처럼 하나의 메모리 공간에는 8개의 비트로 이루어진 1바이트의 데이터가 저장된다. 따라서 메모리의 주소 또한 1바이트씩 증가되며, 낮은 주소부터 차례대로 데이터가 저장된다. 위의 그림에서 변수의 길이가 총 4개의 메모리 공간을 포함하므로, 해당 변수에는 4바이트의 데이터가 저장되어 있다.
  • 이때 변수의 이름은 첫 번째 메모리 주소인 0x10만을 가리키게 된다. 따라서 변수의 길이가 4이며, 변수가 어떤 형태로 구성되는지도 알아야만 해당 변수에서 데이터를 올바르게 참조할 수 있다.

 

변수의 선언

  • C언어에서는 변수를 사용하기 전에 반드시 먼저 해당 변수를 저장하기 위한 메모리 공간을 할당받아야 한다. 이렇게 해당 변수만을 위한 메모리 공간을 할당받는 행위를 변수의 선언이라고 부른다. 만약 선언되지 않은 변수를 사용하려고 하면, C 컴파일러는 오류를 발생시킨다.

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

  • 이 방법은 먼저 변수를 선언하여 메모리 공간만을 할당받고, 나중에 변수를 초기화하는 방법이다.
타입 변수이름;
  • 아래 예제처럼 정수를 저장하기 위한 메모리 공간을 할당받으면, 반드시 해당 타입의 데이터만을 저장해야 한다. 그렇지 않고 다른 타입의 데이터를 저장할 경우에는 저장된 데이터에 변형 및 손실이 일어날 수도 있다.
int num;
...
num = 20;
  • 변수의 초기화란 해당 변수를 사용할 수 있도록 초기값을 설정하는 행위로, 초기화되지 않은 변수에는 아무 의미 없는 값인 쓰레깃값만이 들어가 있다.
int num;
printf("%d", num);
  • 위의 예제에서 변수 num은 선언만 하고 아직 초기화되지 않았지만 printf() 함수에서 변수 num을 사용하여 해당 변수에 저장된 값을 출력하려고 하고 있다. 이 경우에 C 컴파일러는 오류를 발생시키지는 않겠지만, 프로그램은 사용자가 의도하지 않은 결과를 출력하므로 C언어에서는 초기화되지 않은 변수는 절대로 사용해서는 안된다.

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

  • C언어에서 변수는 선언과 동시에 그 값을 초기화할 수 있다.
  • 선언하고자 하는 변수들의 타입만 같다면 여러 변수를 동시에 선언할 수도 있지만 선언하고자 하는 변수의 타입이 서로 다르면 동시에 선언할 수 없다.
1. 타입 변수이름[, 변수이름];
2. 타입 변수이름 = 초깃값[, 변수이름 = 초깃값];
int num01, num02;
double num03 = 1.23, num04 = 4.56;

 

상수(constant)

  • 상수(constant)란 변수와 마찬가지로 데이터를 저장할 수 있는 메모리 공간을 의미한다. 하지만 상수는 변수와 다르게 프로그램이 실행되는 동안 상수에 저장된 데이터는 변경할 수 없다.

리터럴 상수(literal constant)

  • 리터럴 상수(literal constant)는 변수와는 달리 데이터가 저장된 메모리 공간을 가리키는 이름을 가지고 있지 않다.
  • C언어에서는 적절한 메모리 공간을 할당받기 위하여, 기본적으로 변수든 상수든 타입을 가지게 된다. 리터럴 상수는 타입에 따라 정수형 리터럴 상수, 실수형 리터럴 상수, 문자형 리터럴 상수 등으로 구분할 수 있다.
    • 정수형 리터럴 상수는 123, -456과 같이 아라비아 숫자와 부호로 직접 표현됩니다.
    • 실수형 리터럴 상수는 3.14, -45.6과 같이 소수 부분을 가지는 아라비아 숫자로 표현됩니다.
    • 문자형 리터럴 상수는 'a', 'Z'와 같이 따옴표('')로 감싸진 문자로 표현됩니다.
123  // 정수형 리터럴 상수
3.14 // 실수형 리터럴 상수
'a'  // 문자형 리터럴 상수

심볼릭 상수(symbolic constant)

  • 심볼릭 상수(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개의 비트 중 최고값을 갖는 비트를 의미한다.

https://www.tcpschool.com/c/c_datatype_basic

  • 정수형 데이터의 타입을 결정할 때에는 반드시 자신이 사용하고자 하는 데이터의 최대 크기를 고려해야 한다. 해당 타입이 표현할 수 있는 범위를 벗어난 데이터를 저장하면, 오버플로우가 발생해 전혀 다른 값이 저장될 수 있기 때문이다.
  • 오버플로우(overflow)란 해당 타입이 표현할 수 있는 최대 범위보다 큰 수를 저장할 때 발생하는 현상을 가리킨다. 오버플로우가 발생하면 최상위 비트(MSB)를 벗어난 데이터가 인접 비트를 덮어쓰므로, 잘못된 결과를 얻을 수 있다. 또한, 언더플로우(underflow)란 해당 타입이 표현할 수 있는 최소 범위보다 작은 수를 저장할 때 발생하는 현상을 가리킨다.
int num = 2147483647; // int형 타입이 저장할 수 있는 최댓값인 2의31승 - 1
printf("변수 num에 저장된 값은 %d입니다.\n", num);    

num = 2147483648;     // int형 타입이 저장할 수 없는 숫자인 2의31승
printf("변수 num에 저장된 값은 %d입니다.\n", num);

// 변수 num에 저장된 값은 2147483647입니다.
// 변수 num에 저장된 값은 -2147483648입니다.  // 양수로 지정했는데 음수로 반환됨

실수형 타입

  • C언어에서 실수란 소수부나 지수가 있는 수를 가리키며, 정수보다 훨씬 더 넓은 표현 범위를 가진다. 하지만 컴퓨터에서 실수를 표현하는 방식은 반드시 오차가 발생하는 기술적 한계를 지닌다. 이러한 실수형 데이터의 오차는 C언어뿐만 아니라 모든 프로그래밍 언어에서 발생하는 공통된 문제다.

float num01 = 3.1415926535897932;  // float 타입의 유효 자릿수는 소수점 6자리
printf("변수 pi에 저장된 값은 %.20f입니다.\n", num01);    

double num02 = 3.1415926535897932; // double 타입의 유효 자릿수는 소수점 16자리
printf("변수 pi에 저장된 값은 %.20f입니다.\n", num02);

// 변수 num01에 저장된 값은 3.14159274101257324219입니다. // 소수점 6자리까지만 정확
// 변수 num02에 저장된 값은 3.14159265358979311600입니다. // 소수점 15자리까지만 정확
  • 실수형 데이터의 타입을 결정할 때는 표현 범위 이외에도 유효 자릿수를 반드시 고려해야 한다.

문자형 타입

  • C언어에서 문자형 데이터란 문자 하나를 표현할 수 있는 타입을 의미한다.
  • 컴퓨터는 2진수밖에 인식하지 못하므로, 문자도 숫자로 표현해야 컴퓨터가 인식할 수 있다. 따라서 어떤 문자를 어떤 숫자에 대응시킬 것인가에 대한 약속이 필요해진다. 이러한 약속 중에서 가장 많이 사용되는 것이 바로 아스키코드(ASCII)입다.
  • 아스키코드(ASCII)는 영문 대소문자를 사용하는 7비트의 문자 인코딩 방식이다. 아스키코드는 문자를 7비트로 표현하므로, 총 128개의 문자를 표현할 수 있다.
  • 아스키코드의 구성은 다음과 같다.
    • 출력할 수 없는 33개의 문자
    • 출력할 수 있는 52개의 영문 대소문자, 10개의 숫자, 32개의 특수 문자와 1개의 공백 문자

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

// 변수 ch에 저장된 값은 a입니다.
// 변수 ch에 저장된 값은 97입니다.  // 아스키코드

 

타입 변환(type conversion)

  • C언어에서 다른 타입끼리의 연산은 우선 피연산자들을 모두 같은 타입으로 만든 후에 수행된다. 이 때 하나의 타입을 다른 타입으로 바꾸는 행위를 타입 변환(type conversion)이라고 한다.
  • 표현 범위가 좁은 타입에서 표현 범위가 더 넓은 타입으로의 타입 변환은 큰 문제가 되지 않지만 반대의 경우인 표현 범위가 좁은 타입으로의 타입 변환에서는 데이터의 손실이 발생한다.

묵시적 타입 변환(자동 타입 변환, 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);

//    ch에 저장된 값은 -56입니다.
// num01에 저장된 값은 3입니다.
// num02에 저장된 값은 5.000000입니다.
  • 위의 예제에서는 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);  

// result01에 저장된 값은 8.140000입니다.
// result02에 저장된 값은 8.140000입니다.
  • 위의 예제에서 첫 번째 연산은 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);

// result01에 저장된 값은 0.000000입니다.
// result02에 저장된 값은 0.250000입니다.
  • 위의 예제에서 첫 번째 연산의 결괏값은 0.000000인데, 그 이유는 산술 연산에 대한 결괏값의 타입은 피연산자의 타입과 언제나 일치하기 때문이다. 즉 int형 데이터끼리의 산술 연산에 대한 결괏값은 언제나 int형 데이터로 나온다. 따라서 두 번째 연산에서처럼 하나의 피연산자를 명시적으로 double형으로 지정해야만 정확한 결괏값을 얻을 수 있다.

 

Reference

728x90
반응형