SafeInt
사용 목적
SafeInt는 정수 연산에 있어서 발생할 수 있는 오버플로우를 방지하는 목적으로 사용
C++ 의 템플릿으로 만들어졌으며, char형에서 __Int64(long long)형 까지 모든 정수형 사용 가능
정수 연산을 통한 오버플로우나, 0으로 나누었을때 발생하는 오버플로우 감지 가능
기본 정수 자료형을 사용 했을시
예제 소스 - unsigned int
#include <iostream>
int main()
{
unsigned int X1 = 1234567;
unsigned int X2 = 1234567;
unsigned int X3 = X1 * X2;
std::cout << "X3 = " << X3 << std::endl;
}
실행 결과
위와 같이 unsigned int 형으로 계산 했을 때의 값은 정확한 값이 나오지 않는다.
정확히 계산된 값( 윈도우 계산기 사용 )
SafeInt를 사용했을 시
예제소스 - SafeInt<unsigned int>
#include <iostream>
#include <safeint.h>
using namespace msl::utilities;
int main()
{
SafeInt<unsigned int> X1(1234567);
SafeInt<unsigned int> X2(1234567);
SafeInt<unsigned int> X3 = X1 * X2;
}
똑같은 계산을 safeint를 적용하여 계산하면,
위와같은 오류를 내뱉는데, 이유는 오버플로우가 발생했기 떄문.
이렇게 오버플로우가 발생하면 바로 오류를 발생 시키기 때문에
잘못 된 값이 들어간 상태로 코드가 진행 될 일을 방지 할 수 있다
잘못 된 값을 처리하는 방법은 여러가지가 있다.
1. try~catch를 사용한 예외 처리 방법
2. SafeInt의 기본 예외처리 클래스를 상속 받아서 원하는 방식으로 정의
3. SafeInt 함수 사용
1. try~catch 사용 예외처리
예제 소스
#include <iostream>
#include <safeint.h>
using namespace msl::utilities;
int main()
{
SafeInt<unsigned int> X1(1234567);
SafeInt<unsigned int> X2(1234567);
try
{
SafeInt<unsigned int> X3 = X1 * X2;
}
catch (SafeIntException e)
{
std::cout << "overflow!!. ErrorCode : " << e.m_code << std::endl;
}
}
실행결과
위와같이 오버플로우가 발생할시 SafeInt는 예외를 던지며 예외를 catch에서 처리할 수 있다.
2. SafeInt 예외처리 클래스
예제 소스
#include <iostream>
#include <safeint.h>
using namespace msl::utilities;
class MySafeIntException : public SafeIntException
{
public:
static void SafeIntOnOverflow()
{
std::cout << "Overflow 발생!" << std::endl;
}
static void SafeIntOnDivZero()
{
std::cout << "0으로 나누기 발생!" << std::endl;
}
};
int main()
{
SafeInt<unsigned int, MySafeIntException> X1(1234567);
SafeInt<unsigned int, MySafeIntException> X2(1234567);
SafeInt<unsigned int, MySafeIntException> X3 = X1 * X2;
SafeInt<unsigned int, MySafeIntException> X4 = X1 / 0;
}
실행결과
예외처리 기본 클래스를 사용하면 SafeInt 연산중 예외처리가 발생하면, 직접 정의한 함수가 호출이 된다.
예외처리시 중요한 점
1. 예외처리 클래스는 SafeIntException 클래스를 상속 받아야함
2. static void 형으로 SafeIntOntOverflow()와 SafeIntOnDivZero()를 재정의
추가로 매번 SafeInt 인자로 MySafeIntException을 넘겨주었는데 매번 이렇게 넘겨주기 번거롭기 때문에
클래스 탬플릿 인자를 미리 정의 해 놓으면 보다 쉽게 적용 할 수 있다.
예제코드
#include <iostream>
#define _SAFEINT_DEFAULT_ERROR_POLICY MySafeIntException
#include <safeint.h>
using namespace msl::utilities;
class MySafeIntException : public SafeIntException
{
public:
static void SafeIntOnOverflow()
{
std::cout << "Overflow 발생!" << std::endl;
}
static void SafeIntOnDivZero()
{
std::cout << "0으로 나누기 발생!" << std::endl;
}
};
int main()
{
SafeInt<unsigned int> X1(1234567);
SafeInt<unsigned int> X2(1234567);
SafeInt<unsigned int> X3 = X1 * X2;
SafeInt<unsigned int> X4 = X1 / 0;
}
실행결과
실행 결과는 전과 같지만, SafeInt를 생성 하는 부분의 매개변수, #define으로 정의 된 부분이 달라진 것을 볼 수있다.
3. SafeInt 라이브러리 함수 사용
정수 오버플로우가 발생하지 않도록 단일 수치 연산을 보호하고 싶을때 사용.
3개이상의 수치연산을 진행 할 때는 함수를 반복해서 사용하기 보다는 SafeInt 클래스를 사용 하는 것이 더 효율적
함수 |
설명 |
SafeAdd |
두 개의 값을 더한다 |
SafeCast |
다른 형으로 캐스팅한다 |
SafeDivide |
두 개의 값으로 나눈다 |
SafeEquals, SafeGreaterThan, SafeGreaterThanEquals, SafeLessThan, SafeLessThanEquals, SafeNotEquals |
2개의 값을 비교한다. 이 함수들을 사용하면 서로 형이 다른 두 개의 값을 형 변환하지 않고 비교할 수 있다 |
SafeModulus |
나머지를 구한다 |
SafeMultiply |
두 개의 값을 곱한다. |
SafeSubtract |
두개의 값을 뺀다. |
예제소스
#include <iostream>
#include <safeint.h>
using namespace msl::utilities;
int main()
{
unsigned char X1 = 123;
unsigned char X2 = 200;
unsigned char X3 = 0;
if (false == SafeAdd(X1, X2, X3)) {
std::cout << "Overflow 발생!" << std::endl;
}
unsigned int A1 = 100;
short A2 = 101;
if (false == SafeEquals(A1, A2)) {
std::cout << "A1와 A2는 서로 다릅니다" << std::endl;
}
return 0;
}
실행결과
위와같이 SafeInt 라이브러리 함수들은 bool 값을 return 해준다.
따라서 함수내부 계산에서 오버플로우가 발생했을 때, false를 반환한다.
이를 이용하여 예외처리를 진행 하면된다.
https://vsts2010.tistory.com/530?category=143386
https://docs.microsoft.com/ko-kr/cpp/safeint/safeint-library?view=vs-2019
위 사이트를 참고하여 작성했습니다.
'개발 > C++' 카테고리의 다른 글
[C++] static 멤버 변수, static 멤버 함수에 대해 (+ mutable) (0) | 2021.08.24 |
---|---|
[C++] 생성자, 소멸자, 복사생성자, 복사 대입 연산자, 복사생성 방지에 대한 얘기 (0) | 2021.02.17 |
VS 2017 환경에서 glog 설치 및 적용 방법 (0) | 2020.07.09 |
[EC++] #define 대신 const, enum, inline을 사용해야 하는 이유 (0) | 2020.02.11 |
[EC++] 용어 정리 ( 선언, 정의, 기본생성자, 복사생성자, 초기화, 복사대입연산자 등 ) (0) | 2020.02.10 |
댓글