문타쿠, 공부하다.
[C언어 코딩 도장] Unit 7. 정수 자료형 사용하기 본문
INTRO
"정수 자료형"
정수 자료형 | 서식 지정자 | 최소 크기 | 값의 범위 |
char = signed char |
d, hhd, c(문자) | 1바이트(8비트, 2⁸개) | -128 ~ 127 |
unsigned char | u, hhu, c(문자) | 0 ~ 255 | |
short = short int |
d, hd | 2바이트(16비트, 2¹⁶개) | -32,768 ~ 32,767 |
unsigned short | u, hu | 0 ~ 65,535 | |
int = signed int |
d 또는 i | 4바이트(32비트, 2³²개) | -2,147,483,648 ~ 2,147,483,647 |
unsigned int | u | 0 ~ 4,294,967,295 | |
long = long int |
ld | 4바이트(32비트, 2³²개) | -2,147,483,648 ~ 2,147,483,647 |
unsigned long | lu | 0 ~ 4,294,967,295 | |
long long = long long int |
lld | 8바이트(64비트, 2⁶⁴개) | -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 |
unsigned long long | llu | 0 ~ 18,446,744,073,709,551,615 |
- 정수 자료형은 크게 char, int가 있다.
- 부호(signed, unsigned)와 크기(short, long)를 붙여 변형이 가능하다.
- signed
- 부호 있는 정수를 표현, 생략 가능
- unsigned
- 부호 없는 정수를 표현, 값은 0부터 시작
- 음수를 저장할 필요가 없다면 같은 공간으로 2배의 범위를 저장
- signed
"int와 long은 크기와 범위가 동일한데 도대체 무슨 차이가 있는 것인가?"
int와 long은 크기와 범위가 시스템 아키텍처 및 컴파일러에 따라 다를 수 있으며, 보통 비슷한 크기와 범위를 가지는 정수 데이터 타입이다.
1) 크기와 범위
일반적으로 int는 4바이트이며, 대개 -2,147,483,648에서 2,147,483,647까지의 범위를 가진다.
반면에 long은 4바이트 또는 8바이트일 수 있으며, 8바이트인 경우에는 더 큰 범위를 가질 수 있다.
예를 들어, 64비트 시스템에서 long은 -9,223,372,036,854,775,808에서 9,223,372,036,854,775,807까지의 범위를 가질 수 있다.
2) 사용 목적
int는 대개 정수 연산에 가장 적합한 타입으로 간주되며, 보통 int를 사용하여 일반적인 정수 값들을 저장하고 계산한다.
long은 큰 정수 값이 필요한 경우나 특정 시스템에서 int의 범위를 초과하는 경우에 사용될 수 있다.
3) 메모리 사용
int와 long의 크기 차이는 메모리 사용에 영향을 미치는데, long은 더 큰 범위를 가지므로 더 많은 메모리를 사용하며, 따라서 메모리 효율성이 중요한 경우 int를 사용하는 것이 좋을 수 있다.
4) 이식
코드의 이식성을 고려할 때, int의 크기는 시스템 간에 더 일관적일 가능성이 높다.
long은 시스템에 따라 크기가 다를 수 있으므로 이식성을 고려할 때 주의가 필요하다.
*참조
[C언어] int 와 long 은 무엇이 다를까? (short, short int, int, long int, long, long long)
역사 컴퓨터는 지금의 32bit 64bit 가 아닌 8bit 16bit 가 주도했던 시절이 있었다. 당연하겠지만 64bit 가 아니라 32bit 도 처리할 수 없는 컴퓨터가 많았던 시절이었다. 당시에(아직까지도) CPU 시장을 주
hackerpark.tistory.com
7.1 정수형 변수 선언하기
"부호 있는 정수 자료형"
#include <stdio.h>
int main(void)
{
char c = 65;
short s = 32767;
int i = 1234567890;
long L = -1234567890;
long long LL = -1234567890123456789;
printf("char : %d, %hhd, %c\n", c, c, c);
printf("short : %d, %hd\n", s, s);
printf("int : %d, %i\n", i, i);
printf("long : %ld\n", L);
printf("long long: %lld\n", LL);
return 0;
}
"부호 없는 정수 자료형"
#include <stdio.h>
int main(void)
{
unsigned char uc = 66;
unsigned short us = 65535;
unsigned int ui = 4123456789;
unsigned long uL = 4123456789;
unsigned long long uLL = 12345678901234567890;
printf("unsigned char : %u, %hhu, %c\n", uc, uc, uc);
printf("unsigned short : %u, %hu\n", us, us);
printf("unsigned int : %u\n", ui);
printf("unsigned long : %lu\n", uL);
printf("unsigned long long: %llu\n", uLL);
return 0;
}
7.2 오버플로우와 언더플로우
"오버플로우"
#include <stdio.h>
int main(void)
{
char c = 127 + 1;
short s = 32767 + 1;
int i = 2147483647 + 1;
long L = 2147483647 + 1;
long long LL = 9223372036854775807 + 1;
unsigned char uc = 255 + 1;
unsigned short us = 65535 + 2;
unsigned int ui = 4294967295 + 3;
unsigned long uL = 4294967295 + 4;
unsigned long long uLL = 18446744073709551615 + 5;
printf("오버플로우_부호 있는 정수형\n");
printf("char : %d\n", c);
printf("short : %d\n", s);
printf("int : %d\n", i);
printf("long : %ld\n", L);
printf("long long: %lld\n\n", LL);
printf("오버플로우_부호 없는 정수형\n");
printf("unsigned char : %u\n", uc);
printf("unsigned short : %u\n", us);
printf("unsigned int : %u\n", ui);
printf("unsigned long : %lu\n", uL);
printf("unsigned long long: %llu\n", uLL);
return 0;
}
- 자료형의 최대로 저장할 수 있는 범위 즉, 최댓값을 넘어서면 오버플로우가 발생한다.
- 오버플로우가 발생하면 범위의 최솟값부터 다시 시작하게된다. (부호 없는 정수형의 최솟값은 0)
- 오버플로우 문제는 당장 버그를 일으키지 않지만 언제 터질지 모르는 시한폭탄과 같다. 오버플로우 상황이 발생하면 예상치 못한 버그가 발생하여 원인을 찾기가 매우 힘들기 때문에 기능을 구현하기 전에 사용한 자료형이 적합한지 살펴봐야 한다.
"언더플로우"
#include <stdio.h>
int main(void)
{
char c = -128 - 1;
short s = -32768 - 1;
//int i = -2147483648;
//long L = -2147483648;
//long long LL = -9223372036854775808;
unsigned char uc = 0 - 1;
unsigned short us = 0 - 1;
unsigned int ui = 0 - 1;
unsigned long uL = 0 - 1;
unsigned long long uLL = 0 - 1;
printf("언더플로우_부호 있는 정수형\n");
printf("char : %d\n", c);
printf("short : %d\n\n", s);
//printf("int : %d\n", i);
//printf("long : %ld\n", L);
//printf("long long: %lld\n\n", LL);
printf("언더플로우_부호 없는 정수형\n");
printf("unsigned char : %u\n", uc);
printf("unsigned short : %u\n", us);
printf("unsigned int : %u\n", ui);
printf("unsigned long : %lu\n", uL);
printf("unsigned long long: %llu\n", uLL);
return 0;
}
- 자료형의 최소로 저장할 수 있는 범위 즉, 최솟값보다 작아지면 언더플로우가 발생한다.
- 언더플로우가 발생하면 범위의 최댓값부터 다시 시작하게된다.
"왜 int, long, long long의 최솟값을 할당하면 에러가 발생하나?"
*error C4146
컴파일러 경고(수준 2) C4146
자세한 정보: 컴파일러 경고(수준 2) C4146
learn.microsoft.com
아래 코드처럼 간접적(?)으로 최솟값을 할당하고 언더플로우 발생시키는건 잘 출력된다...?!
7.3 자료형 크기 구하기
"sizeof 연산자"
- 자료형의 크기를 바이트 단위로 구하는 연산자
- 부호 있는 정수형의 서식 지정자는 zd, 부호 없는 정수형 및 size_t의 형식 지정자는 zu
- sizeof 변수 // sizeof(자료형) // sizeof(변수)
- sizeof 뒤에 ()가 있어 함수로 착각할 수 있는데, sizeof()는 연산자임을 명심하자.
#include <stdio.h>
int main(void)
{
printf("sizeof 변수\n");
char c;
unsigned char uc;
printf(" char: %zd바이트\n", sizeof c);
printf(" unsigned char: %zu바이트\n\n", sizeof uc);
printf("sizeof(자료형)\n");
printf(" short: %zd바이트\n", sizeof(short));
printf(" unsigned short: %zu바이트\n\n", sizeof(unsigned short));
printf("sizeof(변수)\n");
int i;
unsigned int ui;
printf(" int: %zd바이트\n", sizeof(i));
printf(" unsigned int: %zu바이트\n\n", sizeof(ui));
long num1 = 0;
int num1_size = sizeof(num1);
printf("num1은 %d바이트 long 타입입니다.\n\n", num1_size);
long long num2 = 0;
unsigned int num2_size = sizeof(num2);
printf("num2는 %u바이트 long long 타입입니다.\n\n", num2_size);
return 0;
}
#include <stdio.h>
int main(void)
{
char c;
short s;
int i;
long L;
long long LL;
size_t c_size = sizeof(c);
size_t s_size = sizeof(s);
size_t i_size = sizeof(i);
size_t L_size = sizeof(L);
size_t LL_size = sizeof(LL);
printf("size_t char : %zu바이트\n", c_size);
printf("size_t short : %zu바이트\n", s_size);
printf("size_t int : %zu바이트\n", i_size);
printf("size_t long : %zu바이트\n", L_size);
printf("size_t long long: %zu바이트\n", LL_size);
return 0;
}
7.4 최솟값과 최댓값 표현하기
- 정수 자료형의 최솟값과 최댓값을 표현하려면 'limits.h' 헤더 파일을 사용해야 한다.
"부호가 있는 정수 자료형의 최솟값과 최댓값"
#include <stdio.h>
#include <limits.h>
int main(void)
{
char min_c = CHAR_MIN;
short min_s = SHRT_MIN;
int min_i = INT_MIN;
long min_L = LONG_MIN;
long long min_LL = LLONG_MIN;
char max_c = CHAR_MAX;
short max_s = SHRT_MAX;
int max_i = INT_MAX;
long max_L = LONG_MAX;
long long max_LL = LLONG_MAX;
printf("부호가 있는 정수 자료형의 최솟값\n");
printf("char의 최솟값 : %d\n", min_c);
printf("short의 최솟값 : %d\n", min_s);
printf("int의 최솟값 : %d\n", min_i);
printf("long의 최솟값 : %ld\n", min_L);
printf("long long의 최솟값: %lld\n\n", min_LL);
printf("부호가 있는 정수 자료형의 최댓값\n");
printf("char의 최댓값 : %d\n", max_c);
printf("short의 최댓값 : %d\n", max_s);
printf("int의 최댓값 : %d\n", max_i);
printf("long의 최댓값 : %ld\n", max_L);
printf("long long의 최댓값: %lld\n", max_LL);
return 0;
}
"부호가 없는 정수 자료형의 최솟값과 최댓값"
#include <stdio.h>
#include <limits.h>
int main(void)
{
unsigned char max_uc = UCHAR_MAX;
unsigned short max_us = USHRT_MAX;
unsigned int max_ui = UINT_MAX;
unsigned long max_uL = ULONG_MAX;
unsigned long long max_uLL = ULLONG_MAX;
printf("부호가 없는 정수 자료형의 최솟값은 0이다.\n\n");
printf("부호가 없는 정수 자료형의 최댓값\n");
printf("unsigned char의 최댓값 : %u\n", max_uc);
printf("unsigned short의 최댓값 : %u\n", max_us);
printf("unsigned int의 최댓값 : %u\n", max_ui);
printf("unsigned long의 최댓값 : %lu\n", max_uL);
printf("unsigned long long의 최댓값: %llu\n", max_uLL);
return 0;
}
7.5 크기가 표시된 정수 자료형 사용하기
- 16비트, 32비트, 64비트 CPU가 나오고, 운영체제가 발전하면서 정수 자료형의 크기도 달라져 왔다. 그래서 정수 자료형 이름은 많은 혼란을 가져왔고 C99 표준부터는 'stdint.h' 헤더 파일이 추가되었다.
#include <stdio.h>
#include <stdint.h>
int main(void)
{
int8_t i8 = -128;
int16_t i16 = 32767;
int32_t i32 = 2147483647;
int64_t i64 = 9223372036854775807;
uint8_t ui8 = 255;
uint16_t ui16 = 65535;
uint32_t ui32 = 4294967295;
uint64_t ui64 = 18446744073709551615;
printf("int8_t : %d\n", i8);
printf("int16_t: %d\n", i16);
printf("int32_t: %d\n", i32);
printf("int64_t: %lld\n\n", i64);
printf("uint8_t : %u\n", ui8);
printf("uint16_t: %u\n", ui16);
printf("uint32_t: %u\n", ui32);
printf("uint64_t: %llu\n\n", ui64);
return 0;
}
- 위와 같은 자료형은 크기를 정확하게 표현해야 하는 파일 압축 및 암호화, 네트워트 프로그래밍을 할 때 특히 유용하며, 일반적인 프로그래밍을 할 때도 처음부터 stdint.h를 사용하는 것이 좋다.
- stdint의 최소, 최대값은 stdint.h 헤더 파일 안에 정의되어 있으므로 limits.h 헤더 파일을 사용하지 않아도 된다.
- 부호 있는 정수의 최솟값: INT8_MIN, INT16_MIN, INT32_MIN, INT64_MIN
- 부호 있는 정수의 최댓값: INT8_MAX, INT16_MAX, INT32_MAX, INT64_MAX
- 부호 없는 정수의 최솟값: 0
- 부호 없는 정수의 최댓값: UINT8_MAX, UINT16_MAX, UINT32_MAX, UINT64_MAX
'C언어 > C언어 코딩 도장' 카테고리의 다른 글
[C언어 코딩 도장] Unit 8. 실수 자료형 사용하기 (0) | 2023.08.17 |
---|---|
[C언어 코딩 도장] Unit 7. 연습문제 및 심사문제 (0) | 2023.08.16 |
[C언어 코딩 도장] Unit 6. 디버거 사용하기 (0) | 2023.08.15 |
[C언어 코딩 도장] Unit 5. 연습문제 및 심사문제 (0) | 2023.08.15 |
[C언어 코딩 도장] Unit 5. 변수 만들기 (0) | 2023.08.15 |