assert
DCL-03. 상수 수식의 값을 테스트할 때는 static assertion을 사용해라
dynamic assert: assert()
- dynamic assert(동적 assert) 기능으로 assert() 함수가 있다.
- assertion 은 취약성이 될 수 있는 소프트웨어의 결점을 찾아 제거하는데 사용되는 효과적인 진단 도구이다.
- 다만, assert() 을 사용하는 것은 몇 가지 제약이 존재한다.
- 일반적인 assertion 도구는 프로그램이 구동 중에 동작하므로 런타임 오버헤드 존재
- 일반적인 assertion 도구의 마지막 동작은 abort()를 호출하는 것이므로 서버, embedded 에서는 사용하기 어렵다.
- assert()는 프로그램을 구동 중 강제 종료 시키기 때문에, 서버나 임베디드(e.g. 차)에서 사용하긴 힘듬
- 그럼에도 불구하고 assert()는 엄청 써야한다
![](https://velog.velcdn.com/images%2Fmarkyang92%2Fpost%2Fffad9422-2f72-4541-82dd-ddb48a83a7fe%2Fimage.png)
편리하기 때문!!
assert의 side effect
- assert와 함께 사용되는 표션식은 side effect를 가지면 안된다.
- 이는 assert 함수가 매크로이기 때문
- 매크로 함수 내에서 값의 할당, 증가, 감소, 메모리 접근, 함수 호출등은 unexpected behaviour
- assert 내에서 증감 금지
1. 부적절한 코드
- assert 내에서 증감 금지
![](https://velog.velcdn.com/images%2Fmarkyang92%2Fpost%2Ff3c90be3-0ea8-44e6-aebe-9c51bd2b60c6%2Fimage.png)
1. 해결방법
- 임시 변수를 따로 두거나 하여 assert 내에서 증감 방지
![](https://velog.velcdn.com/images%2Fmarkyang92%2Fpost%2Fb1bf09bc-a5d4-4c1c-ace5-63ac2aefeb48%2Fimage.png)
static assert: _Static_assert()
- Static assert(정적 assert) 기능으로 _Static_assert()를 C11에서 지원
1. 해결방법
- static assertion(C11)을 사용한다.
![](https://velog.velcdn.com/images%2Fmarkyang92%2Fpost%2F38189420-b627-4f14-be51-3f8dc71d670b%2Fimage.png)
![](https://velog.velcdn.com/images%2Fmarkyang92%2Fpost%2F8408a3f2-06af-498d-9d68-2761d709c1f6%2Fimage.png)
App independent code는 별도 에러 처리 설명이 없는 에러 감지 코드를 제공할 것
- App independent code는 아래의 경우 코드이다.
- 컴파일러나 운영체제와 함께 제공됨
- 제 3자가 제공한 라이브러리
- 내부 개발 용도
- App independent code는 어떤 App에도 dependency가 없기 때문에 Erorr를 처리할 수 없다.
그러나 Error를 감지하고 App에게 report하여 Error를 처하게 해야한다.
1. 부적절한 코드
- 라이브러리 내에서 해결할 수 없는 문제가 발생한 경우, 프로그램을 임의로 중단시키는 것은 좋지 않다.
![](https://velog.velcdn.com/images%2Fmarkyang92%2Fpost%2F8d14d4b7-938d-4cdf-9c6f-1b8740d2c151%2Fimage.png)
1. 해결 방법
- user가 에러 처리를 할 수 있도록 한다.
![](https://velog.velcdn.com/images%2Fmarkyang92%2Fpost%2Fb29ed927-e18e-4f30-bd4d-0c510196d3ea%2Fimage.png)
errno
사용
errno
를 사용하는 라이브러리 호출 하기 전, errno = 0
- 프로그램 시작 시
errno = 0
이다. 어떤 라이브러리에 의해서도 다시 0
으로 설정되지 않는다.
- 에러 발생하면 라이브러리 함수에서
errno != 0
인 값으로 설정할 수 있다.
- 라이브러리 함수가 에러 코드를 설정 한다면,
errno
값을 확인
- 일반적인 에러 감지할 때는 반환 값확인,
errno
는 단지 해당 에러가 무엇인지 파악할 때만 사용해야한다.
![](https://velog.velcdn.com/images%2Fmarkyang92%2Fpost%2F23ea0458-5d50-4525-9654-ff20153d715f%2Fimage.png)
- C99 표준에서는
fopen()
함수에서 에러가 발생했을 때, errno
값을 설정하는 것을 보장하지 않는다.
![](https://velog.velcdn.com/images%2Fmarkyang92%2Fpost%2F2225b2d1-686a-4f77-8d06-9571a7236a85%2Fimage.png)
fopen()
때는 errno
를 설정하지 말 것
- 하지만 POSIX에서는
fopen()
함수에 대한 errno
값을 설정한다고 함
![](https://velog.velcdn.com/images%2Fmarkyang92%2Fpost%2Fe601c888-e3a4-43de-85ec-a17fc534d830%2Fimage.png)
컴파일 시 높은 경고 메시지 옵션
- 사용하고 있는 컴파일러에서 가장 높은 수준의 경고 레벨을 주 코드를 컴파일하고 발생하는 모든 경고는 코드 수정을 통해 제거하는 것이 좋다.
- Warning은 다가올 재앙이기 때문!!
논리적으로 완전해지도록 노력
- SW Weakness는 프로그래머가 데이터의 모든 가능한 상태를 생각하지 못할 때 발생할 수 있다.
1. 부적절한 코드
- C에서 열거형 상수는 정수(int) 타입을 갖기 때문에 다음의 코드는 아무런 문제가 되지 않는다.
![](https://velog.velcdn.com/images%2Fmarkyang92%2Fpost%2Fb2846be6-422e-4b85-84d7-64c702c5cfc9%2Fimage.png)
time_t 값 직접 조작 X
- time_t 타입은 시간을 표시할 수 있는 산술적인 타입으로 정의되어 있다. 하지만 이 산술 타입이 어떻게 시간으로 인코딩되는지는 정의되어 있지 않다. 때문에 이 타입에 대해 직접 산술 연산을 수행하는 것은 안전하지 않다.
1. 부적절한 코드
- time_t 값을 사용자가 직접 산술연산하고 있다.
![](https://velog.velcdn.com/images%2Fmarkyang92%2Fpost%2F09e3b44e-6fa1-4c20-9cda-8eb85295f01e%2Fimage.png)
1. 해결 방법
- 시간차를 구하기 위해 difftime() 함수를 사용한다.
![](https://velog.velcdn.com/images%2Fmarkyang92%2Fpost%2Fa75f78e5-b32a-42ee-a6e6-c2ac0efcc447%2Fimage.png)