위와 같은 모든 경우들에서 C++은 데이터를 한 자료형에서 다른 자료형으로 변환하기 위해 형변환을 한다.
기본적인 형 변환의 두 가지 유형
암시적 형변환: 컴파일러가 자동으로 하나의 기본 자료형을 다른 자료형으로 변환한다. 자동 형 변환이라고 불린다.
명시적 형변환: 형 변환을 하기위해 형 변환 연산자를 사용한다.
암시적 형 변환
암시적인 형 변환은 하나의 기본 자료형이 예상되지만, 다른 기본 자료형이 제공될 때마다 수행된다.
변환을 수행하는 방법을 컴파일러에 명시적으로 알려주지 않는다.
숫자 승격
한 자료형의 값이 더 큰 유사한 자료형의 값으로 변환하는 경우, 숫자 승격이 일어난다.
숫자 승격은 항상 안전하며, 데이터 손실이 발생하지 않는다.
long l(64);
double d(0.12f);
숫자 변환
큰 자료형의 값이 더 작은 유사한 자료형의 값으로 변환하거나 서로 다른 자료형 간에 변환이 일어나는 경우 숫자 변환이 일어난다.
short s = 2; // 더 작은 유사한 자료형의 값으로 변환
double d = 3; // 서로 다른 자료형 간에 변환
항상 안전한 숫자 승격과는 달리 숫자 변환은 데이터가 손실되거나 그렇지 않을 수도 있다.
이로 인해 숫자 변환이 일어나는 경우엔 컴파일러가 항상 경고를 보낸다.
숫자 변환 시 데이터 손실이 일어나는 경우
범위가 충분히 크기 않은 자료형으로 변환하는 경우
int main()
{
int i = 30000;
char c = i; // int에서 char로 숫자 변환: 30000을 저장하고 표현하기엔 부족
std::cout << static_cast<int>(c);
return 0;
}
부동 소수점 숫자에서 정수로 변환하는 것은 분수 값을 모두 손실시킨다.
int i = 3.5;
std::cout << i;
산술 표현식 평가
표현식을 평가할 때, 컴파일러는 각 표현식을 개별 하위 표현식으로 나눈다.
산술 연산자의 피연산자는 모두 같은 자료형이어야 하므로 컴파일러는 산술 연산을 평가할 시 다음과 같은 규칙을 사용한다.
피연산자의 자료형이 int보다 작은 정수인 경우, int또는 unsigned int로 승격된다.
피연산자의 자료형이 여전히 같지 않으면, 컴파일러는 피연산자 중 더 높은 우선순위의 자료형으로 선언된 피연산자의 자료형으로 다른 피연산자를 암시적 형 변환을 통해 일치시킨다.
피연산자 자료형의 우선순위
long double(highest)
double
float
unsigned long long
long long
unsigned long
long
unsigned int
int(lowest)
명시적 형변환
10 / 4 를 실행할 경우 해당 산술 연산에서는 숫자 승격이 일어나지 않는다. 왜냐하면 10과 4 모두 정수 int 자료형의 값으로 서로 동일한 자료형의 값이기 때문이다.
따라서 10 / 4 의 결과는 정수 2로, 부동 소숫점 숫자가 아니기 때문에 float 자료형의 변수에 대입을 하더라도 소수 부분을 정확히 표현한 값이 저장되지 않고, 2.0이 저장된다.
이렇게 정수가 아닌 부동 소숫점으로 연산함을 표현하는 것이 필요한 경우에 사용할 수 있는 형 변환이 명시적 형 변환이다.
C - style cast
int i1 = 10;
int i2 = 4;
float f = float(i1) / i2;
static_cast
int i1 = 10;
int i2 = 4;
float f = static_cast<float>(i1) / i2; // result : 2.5
static_cast는 하나의 자료형을 다른 자료형으로 변환하는 데 가장 좋은 방법이다.
static_cast의 주요 장점은 컴파일 타임에 타입 검사를 제공하여 부주의한 오류를 만들기가 더 어렵다는 것이다.
satic_cast는 C-style cast보다 덜 강력하여서 실수로 const를 제거하는 등 의도하지 않은 작업을 할 확률을 줄여준다.
암시적 형 변환 중에서 숫자 변환이 일어날 때 컴파일러는 경고문을 띄우는 데, 이 때 암시적 형 변환이 일어나게 두는 것이 아닌 static_cast를 이용해서 명시적 형 변환을 하면 컴파일러가 경고문을 띄우지 않는다.
흐름 제어 구문
조건문
조건문은 지정된 조건에 따라 실행 흐름을 제어하는 문장이다.
C++에서 사용할 수 있는 조건문은 if문과 switch 문이 있다.
if 문 : 조건의 참, 거짓에 따라 문장을 선택적으로 실행할 수 있도록 하는 구문
if(조건)
문장 1; // 조건이 참일 때 실행할 문장
else
문장 2; // 조건이 거짓일 때 실행할 문자
if(a < b) {
int t = a; // t는 블록 내에서만 사용되는 지역 변수
a = b;
b = t;
}
switch 문 : 만약 정수 자료형에 해당되는 수식의 값에 따라 해당되는 처리를 하고자 할 때에는 if문 대신 switch 문을 사용하면 편리하다.
switch(정수형_수식) {
case 값1:
문장1; // 정수형 수식의 값이 값1일 때 실행할 문장들 나열
break; // switch 문을 빠져 나가게 함
case 값2:
문장2; // 정수형 수식의 값이 값2일 때 실행할 문장들 나열
break; // switch 문을 빠져 나가게 함
case 값3:
문장3; // 정수형 수식의 값이 값3일 때 실행할 문장들 나열
break; // switch 문을 빠져 나가게 함
...
default: // 정수형 수식의 값과 일치하는 case 값이 없을 때
문장 n; // 실행할 문장들을 나열
}
switch(score/10){
case 10: // score가 100이면 아래로 진행
cases 9: // score가 90~100인 경우
grade = 'A';
break;
cases 8: // score가 80~89인 경우
grade = 'B';
break;
cases 7: // score가 70~79인 경우
grade = 'C';
break;
cases 6: // score가 60~69인 경우
grade = 'D';
break;
default: // 그 외의 모든 경우
grade = 'F';
}
반복문
반복문은 일정 범위의 문장을 반복하여 실행하고자 할 때 사용하는 구문으로, for, while, do - while 구문이 있다.
for 문
for(초기화; 반복 조건; 증감)
문장;
int val, total = 0;
for(int i = 0; i < 10; i++) {
std::cin >> val;
total += val;
}
for(원소 선언: 데이터 집합)
문장;
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int sum = 0;
for(int a: arr)
sum += a;
std::cout << "합계 = " << sum << endl;
int val, total = 0;
cin >> val;
while(val > 0) {
total += val;
cin >> val;
}
do - while 문
do {
문장;
}while (반복 조건);
break 및 continue 명령
반복문의 흐름은 필요에 따라 break 및 continue 명령으로 바꿀 수 있다.
break 명령은 반복문을 빠져나가게 하며, continue 명령은 반복문 블록의 나머지 부분을 건너뛰게 한다.
while (조건) {
반복 문장1;
반복 문장2;
break; // 아래 문장을 실행하지 않고 while 문을 빠져나가고 다음 문장 실행
반복문장3;
반복문장4;
}
다음문장;
while (조건) {
반복 문장1;
반복 문장2;
continue; // 아래 문장을 실행하지 않고 while문의 조건 검사로 이동
반복문장3;
반복문장4;
}
다음문장;
goto 문
goto 문은 CPU가 코드의 다른 지점으로 점프하도록 하는 제어 흐름 명령문
점프하는 지점은 문 라벨(statement label) :을 이용하여 식별된다.
#include <iostream>
#include <cmath> // for sqrt() function
int main()
{
double x;
tryAgain: // this is a statement label
std::cout << "Enter a non-negative number";
std::cin >> x;
if (x < 0.0)
goto tryAgain; // this is the goto statement
std::cout << "The sqrt of " << x << " is " << sqrt(x) << std::endl;
return 0;
}
만약 음수를 입력하면 프로그램은 goto 문을 사용하여 tryAgain 라벨로 다시 이동한다.
goto 문과 문 라벨 :은 같은 함수 내에 나타나야 한다.
goto문과 동일한 블록에서 초기화된 변수를 건너뛰어 점프할 수는 없다.
int main()
{
goto skip; // invalid forward jump
int x = 5;
skip:
x += 3; // what would this even evaluate to?
return 0;
}