C++ Primer 03
학습목표
- C++의 변수 이름을 정하는 규칙
- C++에 내장된 정수형 :
unsigned long
,long
,unsigned int
,int
,unsigned short
,short
,char
,unsigned char
,signed char
,bool
- C++11에서 추가된 변수형 :
unsigned long long
,long long
- 여러 정수형의 시스템 한계값을 나타내는
climits
파일 - 여러 정수형의 수치 상수들
const
제한자를 사용하여 기호 상수 만들기- C++에 내장된 부동 소수점형 :
float
,double
,long double
- 여러 부동 소수점형의 시스템 한계값을 나타내는
cfloat
파일 - 여러 부동 소수점형의 수치 상수들
- C++의 산술 연산자
- 자동 데이터형 변환
- 강제 데이터형 변환
3.1 간단한 변수
변수 이름
의미를 쉽게 알 수 있는 변수 이름을 사용할 것을 권장
C++에서 변수명을 설정할 때는 지켜야하는 규칙이 있음
- 변수명에는 영문자, 숫자, 밑줄(_)만 사용 가능
- 숫자를 변수 이름의 첫 문자로 사용할 수 없음
- 변수 이름에서 대문자와 소문자는 별개로 취급
- C++의 키워드는 변수명으로 사용할 수 없음
- 두개의 밑줄 문자로 시작하거나 밑줄문자 + 대문자로 시작하는 이름은 컴파일러와 리소스가 사용하기로 예약되어있음
- 하나의 밑줄 문자로 시작하는 이름은 컴파일러와 리소스가 전역 식별자(global identifier)로 사용하기로 예약되어있음
- 변수명의 길이에는 제한이 없으며 변수명에 쓰인 모든 문자가 유효함
ANSI C(C99)에서는 63개 문자만 유효한것으로 처리함
두 개 이상의 단어를 결합할때는 단어들 사이를 밑줄로 구분하거나 단어들의 첫 문자를 대문자로 쓰는 것이 관례
정수형
소수부가 없는 수, 메모리 용량의 한계가 있으므로 정수들의 부분 집합만을 나타낼 수 있음
C++에서는 데이터형에 따라 서로 다른 크기의 메모리를 사용함
기본 정수형은 크기 순서대로 char
- short
- int
- long
- long long
이 있음
기본형들에 대해 signed
형(양수 + 음수값 모두 포함)과 unsigned
형(양수값만 포함)이 각각 따로 존재
short / int / long / long long
C++은 해당 데이터형들의 최소 크기만을 지정하여 융통성있는 표준을 제공함
short
형은 최소한 16비트 폭을 가짐int
형은 최소한short
형 크기 이상, 일반적으로는 32비트를 사용long
형은 최소한 32비트 폭을 가지며int
형 크기 이상long long
형은 최소한 64비트 폭을 가지며long
형 크기 이상
sizeof
연산자로 변수나 데이터형의 크기를 바이트 단위로 확인할 수 있음
또는 climits
헤더 파일에서 정의된 값을 통해서도 확인할 수 있음
// limits.cpp
#include <iostream>
#include <climits>
int main()
{
using namespace std;
int n_int = INT_MAX;
short n_short = SHRT_MAX;
long n_long = LONG_MAX;
long long n_llong = LLONG_MAX;
cout << "int는 " << sizeof (int) << " 바이트이다." << endl;
cout << "short는 " << sizeof n_short << " 바이트이다." << endl;
cout << "long은 " << sizeof n_long << " 바이트이다." << endl << endl;
cout << "long long은 " << sizeof n_llong << " 바이트이다." << endl;
cout << endl;
cout << "최댓값 : " << endl;
cout << "int : " << n_int << endl;
cout << "short : " << n_short << endl;
cout << "long : " << n_long << endl << endl;
cout << "long long : " << n_llong << endl << endl;
cout << "int의 최솟값 = " << INT_MIN << endl;
cout << "바이트 당 비트수 = " << CHAR_BIT << endl;
return 0;
}
sizeof
를 데이터형 이름에 사용할시 괄호가 필요, 변수명에 사용할시에는 괄호가 없어도 상관없음
INT_MAX
, CHAR_BIT
(CHAR형의 비트 수 = 바이트 당 비트 수) 등은 climits
파일에 정의되어있는 기호 상수임
#define SHORT_MAX 32767
의 형식으로 정의되어있으며,#define
은#include
와 같은 전처리 지시자임#define
지시자가INT_MAX
가 나올때마다 32767로 대체하라고 전처리기에게 지시- 결과적으로 소스 코드 내의 모든
INT_MAX
가 대체되어 컴파일 과정으로 넘겨짐 - 단, 이는 C로부터의 유물이며 C++에서는
const
키워드를 사용하는 더 좋은 방법이 있음
정의된 변수를 초기화하지 않으면 변수의 값은 미확정(undefined) 상태가 되어 그 메모리 위치에 우연히 남아있던 것이 해당 변수의 값으로 행세하게 됨
따라서 변수를 선언할 때부터 값을 대입하여 초기화까지 하는 것을 권장함
전통적인 C 스타일의 초기화 문법 : int owls = 101;
C++의 새로운 초기화 문법 : int owls(101);
C++11에서의 초기화 문법 : int owls = { 101 };
/ int owls{ 101 };
중괄호 안이 공백일시 0으로 초기화됨
unsigned형
음수 값을 저장할 수 없는 대신 변수에 저장할 수 있는 최대값이 늘어남
// exceed.cpp
#include <iostream>
#define ZERO 0
#include <climits>
int main()
{
using namespace std;
short Dohee = SHRT_MAX;
unsigned short Insuk = Dohee;
cout << "도희의 계좌에는 " << Dohee << "원이 들어있고, ";
cout << "인숙이의 계좌에도 " << Insuk << "원이 들어있다." << endl;
cout << "각각의 계좌에 1원씩 입금한다." << endl << "이제 ";
Dohee = Dohee + 1;
Insuk = Insuk + 1;
cout << "도희의 잔고는 " << Dohee << "원이 되었고, ";
cout << "인숙이의 잔고는 " << Insuk << "원이 되었다." << endl;
cout << "이럴수가! 도희가 나 몰래 대출을 했나?" << endl;
Dohee = ZERO;
Insuk = ZERO;
cout << "도희의 계좌에는 " << Dohee << "원이 들어있고, ";
cout << "인숙이의 계좌에도 " << Insuk << "원이 들어있다." << endl;
cout << "각각의 계좌에 1원씩 인출한다." << endl << "이제 ";
Dohee = Dohee - 1;
Insuk = Insuk - 1;
cout << "도희의 잔고는 " << Dohee << "원이 되었고, ";
cout << "인숙이의 잔고는 " << Insuk << "원이 되었다." << endl;
cout << "이럴수가! 인숙이가 복권에 당첨되었나?" << endl;
return 0;
}
데이터형의 표현 한계값을 벗어날시(오버플로우 또는 언더플로우) unsigned
정수형의 경우 항상 반대편 끝으로 넘어감
C++에서는 signed
정수형의 경우도 대부분 동일하게 동작하지만, 보장할 수는 없음
정수형 선택
일반적으로는 컴퓨터가 가장 효율적으로 처리하는 정수 형식인 int
형을 사용하는 것을 권장
음수가 될 수 없는 수를 나타낼 때는 unsigned
정수형을 사용해 보다 큰 값을 나타냄
수를 나타내기 위해 16비트보다 더 많이 필요한 수는 long
형을 사용함
int
형이 32비트인 경우라도long
형을 사용하는데, 이는 16비트int
형을 사용하는 시스템으로 이식할 경우에 오동작을 막기 위함임- 이십억으로도 모자랄 경우에는
long long
형을 사용
short
형이 int
형보다 크기가 작을 경우에는 메모리 절약을 위해 short
형을 사용함
- 메모리 절약이 중요하다면 두 데이터형의 크기가 같을 경우에도
short
형을 사용해야함 - 16비트
int
형을 사용하는 시스템에서 32비트int
형을 사용하는 시스템으로 프로그램을 이식할경우,int
형의 경우 두 배의 메모리를 요구하게 되지만short
형은 그렇지 않아 비트를 절약할 수 있음
1바이트만 필요할 경우에는 char
형을 사용할 수 있음
정수형 상수
// hexoct1.cpp
#include <iostream>
int main()
{
using namespace std;
int chest = 42;
int waist = 0x42;
int inseam = 042;
cout << "손님 몸매는 한마디로 끝내줍니다!\n";
cout << "가슴둘레 " << chest << "\n";
cout << "허리둘레 " << waist << "\n";
cout << "인심길이 " << inseam << "\n";
return 0;
}
정수형 상수 : 프로그램에 직접 써 넣는 정수
- 처음 숫자가 1~9 : 10진수
- 처음 숫자가 0, 두번째 숫자가 1~7 : 8진수
- 처음 두개의 문자가 0x 혹은 0X : 16진수
cout
은 기본적으로 정수를 10진수로 출력
// hexoct2.cpp
#include <iostream>
int main()
{
using namespace std;
int chest = 42;
int waist = 42;
int inseam = 42;
cout << "손님 몸매는 한마디로 끝내줍니다!\n";
cout << "가슴둘레 " << chest << " (10진수)\n";
cout << hex;
cout << "허리둘레 " << waist << " (16진수)\n";
cout << oct;
cout << "인심길이 " << inseam << " (8진수)\n";
return 0;
}
cout << hex
구문은 cout
이 정수를 나타내는 방식을 변경함
cout << dec
: 십진수로 변경cout << hex
: 16진수로 변경cout << oct
: 8진수로 변경
C++가 상수의 데이터형을 결정하는 방법
cout << "Year = " << 1492 << "\n";
위와 같이 정수 형 상수를 저장하는 경우에 C++에서는 일반적으로 모두 int
형으로 저장됨
단, 접미어를 붙었을 때는 해당 접미어에 맞는 데이터형으로 저장됨
접미어가 없는 10진 정수는 int
, long
, long long
형 중에서 해당 정수가 범위 내에 속하는 가장 작은 크기의 데이터형으로 저장됨
접미어가 없는 16진 / 8진 정수는 int
, unsigned int
, long
, unsigned long
, long long
, unsigned long long
형 중에서 해당 정수가 범위 내에 속하는 가장 작은 크기의 데이터형으로 저장됨
char형
// chartype.cpp
#include <iostream>
int main()
{
using namespace std;
char ch;
cout << "원하는 문자 하나를 입력하시오 : " << endl;
cin >> ch;
cout << "감사합니다. ";
cout << "당신이 입력한 문자는 " << ch << "입니다." << endl;
return 0;
}
각 문자는 특정 정수와 일대일로 대응하며, 문자 세트는 ASCII
를 일반적으로 사용함
그러나 ASCII
는 제한이 크기 때문에 C++에서는 보다 범용적인 Unicode
를 사용할 수 있는 확장 문자형을 지원함
위 예제에서 입력된 문자는 해당 문자에 대응하는 정수로 변수 ch
에 저장되며, 이를 출력할 때는 해당 정수에 대응하는 문자로 변환되어 출력됨
// morechar.cpp
#include <iostream>
int main()
{
using namespace std;
char ch = 'M';
int i = ch;
cout << ch << "의 ASCII 코드는 " << i << "입니다." << endl;
cout << "이 문자 코드에 1을 더해보겠습니다." << endl;
ch = ch + 1;
i = ch;
cout << ch << "의 ASCII 코드는 " << i << "입니다." << endl;
cout << "cout.put(ch)를 사용하여 char형 변수 ch를 화면에 출력 : ";
cout.put(ch);
cout.put('!');
cout << endl << "종료" << endl;
return 0;
}
char
형 변수도 정수형 변수이므로 정수 연산을 적용할 수 있음
cout.put()
: ostream
클래스에 포함되어있는 put()
이라는 멤버 함수를 cout
객체를 통해 사용
- 멤버 함수 : 클래스에 속하며 해당 클래스의 특정 객체를 통해서만 사용할 수 있음
마침표로 객체 이름과 함수 이름을 연결하여 사용하며, 이 때의 마침표는 멤버 연산자(membership operator)로 작동함 - C++ Release 2.0 이전에
cout
이 문자 상수를int
형으로 저장했기 때문에 사용된 함수
'A', ' '
의 형식과 같이 작은따옴표로 문자를 둘러싸는 것으로 문자 상수를 표기
특정 코드 체계에 종속적이지 않기 때문에 수치 코드를 사용하는 것보다 좋은 방식임
키보드로 직접 입력할 수 없거나, C++에서 특별한 의미가 부여된 문자(문자열 분리로 사용되는 큰따옴표 등)들은 이스케이프 시퀀스(escape sequence)라는 특수한 표기법을 사용함
'\n', '\t', '\\'
등- 이스케이프 시퀀스 역시 하나의 문자로 취급되기 때문에 문자 상수로 사용할 때에는 반드시 작은따옴표로 둘러쌓여있어야 함
'\x8', '\010'
의 형식으로 사용되는 수치 이스케이프 시퀀스도 있으나 가능하면'\b'
와 같은 기호 이스케이프 시퀀스를 사용하는것이 권장됨
// bondini.cpp
#include <iostream>
int main()
{
using namespace std;
cout << "\a암호명 \"화려한 외출\" 작전이 방금 개시되었습니다!\n";
cout << "8자리 비밀번호를 입력하십시오 : ________\b\b\b\b\b\b\b\b";
long code;
cin >> code;
cout << "\a입력하신 비밀번호는 " << code << "입니다.\n";
cout << "\a비밀번호가 맞습니다! Z3 계획을 진행하십시오!\n";
return 0;
}
8개의 밑줄 문자가 출력된 후 프로그램은 \b
이스케이프 시퀀스에 해당하는 백스페이스 문자를 사용하여 커서를 첫번째 밑줄 문자 위치로 이동시킴
universal character names
C++ 표준은 기본적인 소스 문자 세트를 지원하는데 더해 확장 소스 문자 세트와 확장 실행 문자 세트를 제공하는 것을 허용함
유니버설 캐릭터 이름(universal character names) : 특정 키보드와는 무관한 국제 문자들을 표현하는 메커니즘
\u 또는 \U
+16진수로 나타낸 ISO 10646(국제 표준 문자 세트) 코드
- C++에서는 유니버설 코드(universal code)가 아닌 유니버설 코드 네임(universal code name)이라는 용어를 사용하는데, 이는 문자에 해당하는 코드가 다양한 시스템에서 그 시스템에 맞는 다양한 인코딩을 가질 수 있기 때문임
즉, 사용자의 소스 코드는 모든 시스템에 대해 동일한 유니버설 코드 네임을 사용할 수 있으나 컴파일러는 해당 코드를 특정 시스템에서 그 시스템에 적절한 내부 코드로 표현할 수 있음
signed char / unsigned char
기본 char
형은 signed
형인지 unsigned
형인지 정해져있지 않으나, 사용자가 명시적으로 제한할 수는 있음
표준 ASCII
문자를 사용할 때는 둘 다 상관없으므로 그냥 char
로 사용하면 됨
확장 char형 : wchar_t
1바이트로 표현할 수 없는 문자 세트의 경우(한국어 등)
- 컴파일러 개발업체가
char
형을 처음부터 2바이트 이상으로 만듬 - 또는 기본 문자 세트와 확장 문자 세트를 동시에 지원
기본 문자 세트는char
형으로, 확장 문자 세트는wchar_t(wide character type)
형으로 나타냄wchar_t
형은 기초 데이터형(underlying type)이라는 정수형과 동일한 크기 및 부호 속성을 가지며, 기초 데이터형은 시스템에 따라unsigned short
형 /int
형 등으로 달라질 수 있음L'P', L"tall"
과 같이 확장 문자 상수나 확장 문자 문자열은 앞에L
을 붙여서 나타냄cin
/cout
는wchar_t
형을 처리할 수 없기 때문에wcin
/wcout
객체가 제공됨
C++11형 : char16_t / char32_t
wchar_t
의 부호와 길이는 가변이기 때문에 문제가 발생할 수 있어 C++11에서는 char16_t(unsigned 16비트)
형과 char32_t(unsigned 32비트)
형을 사용하기도 함
char16_t
는 접두사로 u를 사용하며 /u00F6 형태의 유니버설 캐릭터 이름과 매칭됨char32_t
는 접두사로 U를 사용하며 /U0000222B 형태의 유니버설 캐릭터 이름과 매칭됨
bool형
참 또는 거짓 중 한가지 값만 가질 수 있는 변수이며, 미리 정의된 true
와 false
로 참과 거짓을 나타냄
어떠한 수치 값이나 포인터 값도 하나의 bool
값으로 묵시적 변환이 가능함
- 0이 아닌 값들은
true
로 변환 - 0 값은
false
로 변환
3.2 const 제한자
상수를 기호 이름으로 나타내면 의미를 파악하기 쉽고, 상수의 값을 바꿀 때도 기호가 정의된 부분만 바꾸면 되어 편리하다는 장점이 있음
const 데이터형 상수이름 = 값
const
는 선언의 의미를 제한하기 때문에 제한자(qualifier)라고 부름- 선언된 기호 상수는 설정할 값을 가진 상수로 고정되어 변경할 수 없음
- 일반적으로 기호 상수는 상수임을 쉽게 알 수 있도록 모두 대문자로 쓰는 것이 관례
- 선언과 동시에 초기화하지 않으면 변경할 수 없는 미확정 값으로 남겨짐
#define
문으로도 기호 상수를 정의할 수 있으나 const
키워드를 사용하는게 더 좋음
const
는 데이터형을 명시적으로 지정할 수 있음- C++의 활동 범위 규칙(scoping rules)에 의해 그 정의를 특정 함수 혹은 파일에서만 사용할 수 있도록 제한할 수 있음
- 활동 범위 규칙 : 어떤 식별자가 서로 다른 여러 모듈에 얼마나 널리 알려지는가를 나타내는 규칙
- 배열이나 구조체와 같은 보다 복잡한 데이터형에도 사용 가능
- C++에서는 C와 달리
const
를 이용하여 배열의 크기를 선언할 수 있음
3.3 부동 소수점수
소수부가 있는 수, 또는 너무 커서 long
형으로 나타낼 수 없는 경우에 부동 소수점형을 사용
컴퓨터는 소수를 기본값과 스케일 두부분으로 나누어 저장하며, 소수점이 스케일에 따라 자리를 옮기기 때문에 부동 소수점형이라고 부름
부동 소수점수 표기
- ‘8.0, 0.0023’과 같은 일반적인 소수점 표기법
- ‘2.52e+8, 8.33E-4’와 같은 지수 표기법(Enotation), E 또는 e를 사용 가능하며 지수는 + / -를 부호로 가질 수 있으나 소수점은 생략할 수 없음
float / double / long double
유효 숫자의 개수와 지수의 최소 허용 범위에 따라 데이터형이 나뉘어짐
지수의 허용 범위는 모두 최소값은 -37 ~, 최대값은 37 ~
float
형은 최소한 32비트 폭을 가짐, 일반적으로 32비트double
형은 최소한 48비트 폭을 가지며float
형 크기 이상, 일반적으로 64비트long double
형은 최소한double
형 크기 이상, 일반적으로 80 / 96 / 128비트
// floatnum.cpp
#include <iostream>
int main()
{
using namespace std;
cout.setf(ios_base::fixed, ios_base::floatfield);
float tub = 10.0 / 3.0;
double mint = 10.0 / 3.0;
const float million = 1.0e6;
cout << "tub = " << tub;
cout << ", a million tubs = " << million * tub;
cout << ",\nten million tubs = ";
cout << "mint = " << mint << "and a million mints = ";
cout << million * mint << endl;
return 0;
}
setf()
함수의 인자로 iostream
에서 제공하는 ios_base::fixed
와 ios_base:: floatfield
를 사용하여 cout
의 출력 포맷을 고정 소수점으로 변경함
float
형의 유효숫자는 6개, double
형의 유효숫자는 15개이기 때문에 위 코드에서 두 변수의 출력 결과가 다르며, double
형이 정밀도가 더 높음
부동 소수점형 상수
기본적으로 double
형으로저장됨
- 접미어로 f 또는 F를 붙이면
float
형으로 저장됨 - 접미어로 l 또는 L을 붙이면
long double
형으로 저장됨
부동 소수점수 장단점
부동 소수점수는 정수가 아닌 실수를 표현 가능하며, 스케일을 사용함으로써 매우 큰 범위의 값을 나타낼 수 있다는 장점이 있음
그러나 정수 연산보다 속도가 느리며, 정밀도를 잃을 수 있다는 단점이 있음
// fltadd.cpp
#include <iostream>
int main()
{
using namespace std;
float a = 2.34E+22f;
float b = a + 1.0f;
cout << "a = " << a << endl;
cout << "b - a = " << b - a << endl;
return 0;
}
b - a의 결과로 1이 출력되는 대신 0이 출력되는데, 이는 a가 소수점 위로 23개의 숫자를 가진 큰 수이기 때문에 발생되는 문제임
float
형은 처음 6개 또는 7개 숫자까지만 나타낼 수 있기 때문에 23번째 숫자에 1을 더하는 것은 아무런 효과를 가지지 못함
3.4 C++ 산술 연산자
C++은 기본적인 계산을 위한 덧셈 +
, 뺄셈 -
, 곱셈 *
, 나눗셈 /
, 나머지셈 %
의 다섯가지 연산자를 제공함
각각의 연산자는 연산의 대상으로 삼을 피연산자 두개가 필요하며, 연산자와 두개의 피연산자가 결합되어 수식을 구성함
/
연산자의 경우 피연산자가 모두 정수이면 몫은 정수부분만 취함%
연산자의 경우 피연산자는 모두 정수여야하며, 피연산자가 부동 소수점수일 경우 컴파일 에러가 발생함
// arith.cpp
#include <iostream>
int main()
{
using namespace std;
float hats, heads;
cout.setf(ios_base::fixed, ios_base::floatfield);
cout << "수를 하나 입력하십시오 : ";
cin >> hats;
cout << "다른 수를 입력하십시오 : ";
cin >> heads;
cout << "hats = " << hats << "; heads = " << heads << endl;
cout << "hats + heads = " << hats + heads << endl;
cout << "hats - heads = " << hats - heads << endl;
cout << "hats * heads = " << hats * heads << endl;
cout << "hats / heads = " << hats / heads << endl;
return 0;
}
float
형의 한계 때문에 +
연산자의 값이 61.42가 아닌 61.419998이 됨
정밀한 연산을 수행하고싶다면 double
형이나 long double
형을 사용
연산 우선순위와 결합 방향
산술 연산자는 일반 대수학의 우선순위 규칙을 따름
우선순위가 같은 경우 왼쪽->오른쪽 결합이면 왼쪽에 있는 연산자를 먼저 적용하고, 왼쪽<-오른쪽 결합이면 오른쪽 연산자를 먼저 적용함
우선순위 규칙과 결합 방향은 하나의 피연산자에 두 개의 연산자가 걸려있을 때에만 적용됨
나눗셈 연산
// divide.cpp
#include <iostream>
int main()
{
using namespace std;
float hats, heads;
cout.setf(ios_base::fixed, ios_base::floatfield);
cout << "정수 나눗셈 : 9/5 = " << 9 / 5 << endl;
cout << "부동 소수점수 나눗셈 : 9.0/5.0 = " << 9.0 / 5.0 << endl;
cout << "혼합 나숫셈 : 9.0/5 = " << 9.0 / 5 << endl;
cout << "double형 상수 : 1e7/9.0 = " << 1.e7 / 9.0 << endl;
cout << "float형 상수 : 1e7f/9.0f = " << 1.e7f / 9.0f << endl;
return 0;
}
두 피연산자가 모두 정수이면 정수 나눗셈을 수행하여 소수부를 버림
피연산자 중 하나 이상이 부동 소수점수이면 결과는 부동 소수점수가 됨
두 피연산자가 모두 double
형이면 결과는 double
형이 되고, 모두 float
형이면 결과도 float
형이 됨
나머지 연산
// modulus.cpp
#include <iostream>
int main()
{
using namespace std;
const int Lbs_per_stn = 14;
int lbs;
cout << "당신의 체중을 파운드 단위로 입력하십시오 : ";
cin >> lbs;
int stone = lbs / Lbs_per_stn;
int pounds = lbs % Lbs_per_stn;
cout << lbs << " 파운드는 " << stone
<< " 스톤, " << pounds << " 파운드입니다.\n";
return 0;
}
어떠한 양을 서로 다른 정수 단위로 분리할 때 유용
데이터형 변환
C++의 경우 특정 상황에서 데이터를 혼합하여 사용할시 데이터형의 불일치를 해결하기 위해 자동으로 데이터형 변환을 수행함
- 특정 데이터형의 변수에 다른 데이터형의 값을 대입했을 때
- 수식에 데이터형을 혼합하여 사용했을 때
- 함수에 매개변수를 전달할 때
대입 구문에서의 데이터형 변환
범위가 작은 데이터형 값을 범위가 큰 데이터형에 대입하는것은 문제가 되지 않음
단, 그 반대의 경우 문제가 발생할 수 있음
// init.cpp
#include <iostream>
int main()
{
using namespace std;
cout.setf(ios_base::fixed, ios_base::floatfield);
float tree = 3;
int guess = 3.9832;
int debt = 7.2E12;
cout << "tree = " << tree << endl;
cout << "guess = " << guess << endl;
cout << "debt = " << debt << endl;
return 0;
}
double
->float
와 같이 큰 부동 소수점형을 작은 부동 소수점형으로 변환할시 정밀도가 손실되며 원래 값이 변환 데이터형의 범위를 벗어날 경우 결과를 예측할 수 없음- 부동 소수점형을 정수형으로 변환할시 소수부를 잃어버리며 원래 값이 변환 데이터형의 범위를 벗어날 경우 결과를 예측할 수 없음
long
->short
와 같이 큰 정수형을 작은 정수형으로 변환할시 원래 값이 변환 데이터형의 범위를 벗어날 경우 하위 바이트들만 복사됨
C++11에서는 중괄호를 이용한 리스트 초기화가 가능한데, 이 때 변수형이 대입된 값으로 표현될 수 없는 경우인 narrowing
인 경우에는 초기화가 허용되지 않음
단, 변환된 변수가 완벽하게 값을 유지할 수 있는 경우에는 허용될 수 있음
수식에서의 데이터형 변환
bool
, char
, unsigned char
, signed char
, short
형 값은 수식에 사용될 시 모두 int
형으로 변환되어 처리되며, 이를 정수 승급(integral promotion)이라고 함
이는 컴퓨터 내부에서 가장 자연스럽게 처리(가장 빠르게 계산)되는 데이터형이 int
형이기 때문
short
형이int
형보다 크기가 작을 경우에는unsigned short
형이int
형으로 변환short
형과int
형의 크기가 같다면unsigned short
형이unsigned int
형으로 변환wchar_t
형은int
,unsigned int
,long,
unsigned long
형 중 표현 범위를 수용 가능한만큼 충분히 큰 첫번째 데이터형으로 승급- 이는 자료형의 승급시 데이터 손실이 일어나지 않도록 하기 위함
서로 다른 데이터형을 혼합하여 연산할 경우 작은 크기의 데이터형이 큰 크기의 데이터형으로 변환됨
C+11에서는 이러한 변환시 컴파일러가 검사를 진행하는 순서가 존재함
- 한쪽 피연산자가
long double
형이면 다른 피연산자를long double
로 변환 - 그렇지 않을시
double
형인지를 확인, 또다시 아니라면float
형인지를 확인 - 위의 조건에 걸리지 않았을 시 피연산자들이 모두 정수형이므로 정수 승급이 발생
- 양쪽 피연산자가 모두
signed
혹은unsigned
인 경우 크기가 큰 쪽으로 변환 - 한쪽만
unsigned
일 경우unsgined
형 피연산자가signed
형 피연산자보다 상대적으로 크다면 `unsigned 피연산자의 형으로 변환 - 그렇지 않고
signed
형이unsigned
형의 모든 값을 표현 가능하다면unsigned
형 피연산자가signed
형으로 변환 - 위 경우에 해당되지 않을경우 양쪽 모두
signed
형 피연산자의unsigned
형으로 변환
- 양쪽 피연산자가 모두
매개변수 전달시의 형 변환
이 때의 데이터형 변환은 C++의 함수 원형이 제어함
함수 원형이 매개변수를 제어하는 것을 막을 경우 char
형과 short
형에 대해 정수 승급을 수행하며, float
형 매개변수를 double
형으로 변환하여 전달함
데이터형 변환자
C++에서는 데이터형 변환자를 사용하여 강제로 데이터형을 변환할 수 있음
이 때 변수 자체는 변경되지 않고, 대신 지시된 데이터형의 새로운 값을 만들어 수식에 사용할 수 있음
(typeName) value
와 같이 C에서 사용하던 방법이 가능함typeName (value)
와 같이 데이터형 변환이 함수 호출과 비슷하게 보이도록 할 수도 있음- C++에서는
static_cast<typeName> (value)
의 형식으로 데이터형 변환 연산자를 통해 수치 데이터형을 다른 수치 데이터형으로 변환하는데 사용할 수 있음
// typecast.cpp
#include <iostream>
int main()
{
using namespace std;
int auks, bats, coots;
auks = 19.99 + 11.99;
bats = (int) 19.00 + (int) 11.99;
coots = int (19.99) + int (11.99);
cout << "auks = " << auks << ", bats = " << bats;
cout << ", coots = " << coots << endl;
char ch = 'Z';
cout << "코드 " << ch << " 의 값은 ";
cout << int(ch) << endl;
cout << "네, 코드 Z의 값은 ";
cout << static_cast<int>(ch) << endl;
return 0;
}
위 예제에서 auks는 double
형으로 연산이 이루어진 후에 결과값이 int
형으로 변환되고, bats와 coots는 int
형으로 변환이 된 상태로 연산이 이루어졌기 때문에 양쪽의 결과값이 다르게 출력됨
변수 ch의 경우 그냥 출력하면 char
형이기 때문에 문자 Z가 출력되지만, int
형으로 변환하면 해당 문자에 해당하는 ASCII
코드값이 출력됨
C++11에서의 auto 선언
C+11에서는 초기화하는 값을 보고 변수형을 추론할 수 있으며, 따라서 초기화 선언시 데이터형을 쓰지 않고 auto
를 사용할 수 있음
자동으로 변수형을 추론하는 것은 STL(Standard Template Library)를 사용할 때처럼 복잡한 변수형을 다룰 때 유용함
- C++98의 경우
std::vector<double> scores; std::vector<double>:: iterator pv = scores.begin();
- C+11의 경우
std::vector<double> scores; auto pv = scores.begin();
연습문제
-
사용자의 요구에 적합한 데이터형을 골라서 사용할 수 있기 때문
메모리 절약 / 저장 용량 확보 / 계산 속도 등을 고려 -
a)
short a = 80;
b)unsigned int b = 42110;
c)unsigned long c = 3000000000;
-
C++에서는 정수형의 한계를 벗어나지 않도록하는 안전장치를 제공하지 않음
-
33L은
long
형 상수, 33은int
형 상수 -
같지 않음. 다만
ASCII
코드를 사용하는 시스템이라면 ‘A’가ASCII
코드로 65이기 때문에char grade = 65;
와char grade = 'A';
는 같은 기능을 할 수 있음 -
char chr = 88;
,cout << c << endl;
cout.put(char(88));
cout << char(88) << endl;
cout << (char)88 << endl;
-
long
형이 4바이트라면 10자리 수까지(2,147,483,648)까지 저장할 수 있으므로 13자리 유효숫자를 허용하는double
형에 대입할 때 데이터 손실이 발생하지 않음
long long
형은 19자리 수까지 저장할 수 있으므로double
형에 대입할경우 데이터 손실이 발생할 수 있음 -
a)
int a = 8 * 9 + 2;
, a = 74
b)int b = 6 * 3 / 4;
, b = 4
c)int c = 3 / 4 * 6;
, c = 0
d)double d = 6.0 * 3 / 4;
, d = 4.5
e)int e = 15 % 4;
, e = 3 -
int a = int(x1) + int(x2);
- a)
int
형
b)float
형
c)char
형
d)char 32_t
형
e)double
형