오늘은 코드리뷰를 하면서 발견한 _Ret_notnull_
에 대한 궁금증을 풀어보고자 합니다.
단순히 요약하자면 _Ret_notnull_
은 SAL에서 함수가 null을 반환하지 않을 것임을 명시해주는 주석입니다.
하지만 여기까지만보고 끝내면 개발자가 아니겠죠. SAL은 뭐고 왜 사용하는지에 대해 한번 깊게 들어가 봅시다.
SAL은 소스코드 주석 언어로 마이크로소프트가 개발한 코드 분석 도구입니다. 비쥬얼 스튜디오의 경우 <sal.h>에서 확인할 수 있습니다.
SAL을 사용하면 코드의 오류를 분석하여 코드의 잘못된 부분을 빠르게 바로잡을 수 있습니다.
그중 가장 단순한 _In_
은 포인터 매개변수에 주석을 달면 분석기에서 포인터가 null인 경우 오류를 보고해주게 됩니다.
일반적인 코드의 작성은 아래와 같이 작성할 수 있습니다. 그리고 pInt에 nullptr이 들어올 것을 예상해서 if(pInt != nullptr)
과 같은 예외처리를 수행할 수 있습니다.
SAL을 사용하면 이러한 번거로운 작업을 주석 하나로 바로잡을 수 있습니다.(비록 warning이긴 하지만요) 다음 코드를 통해 알아봅시다.
놀랍게도 _In_
을 붙이자마자 컴파일러가 warning C6387: '_Param_(1)' could be '0'
경고를 띄워주는 것을 확인할 수 있습니다.
MSVC 컴파일러의 경우 기본옵션으로 코드분석을 실행하지 않기 때문에 컴파일 과정에서 코드 분석을 하려면 프로젝트 속성 → 코드 분석 → 빌드 중 코드분석 활성화를 Yes로 바꿔줘야합니다.
그리고 컴파일을 실행하게 되면 warning C6387: '_Param_(1)' could be '0'
경고문구가 나오는 것을 확인할 수 있습니다.
_Ret_notnull_
은 뭘까?_Ret_notnull_
은 함수가 결코 null을 반환하지 않을 것임을 명시하는 주석으로 이 주석을 사용하면 항상 유효한 값이 반환되는 것을 (약하게)보장할 수 있습니다. 함수의 앞에 붙여서 다음과 같이 사용할 수 있습니다.
그리고 컴파일 시에 warning C28196: The requirement that 'return!=0' is not satisfied.
의 경고문구를 볼 수 있습니다.
해석하면 "return != 0의 요구사항이 충족되지 않았습니다."로 return 값에 유효한 값을 넣어줘야한다는 의미죠.
_Out_writes_bytes_all_
SAL을 사용하는 가장 대표적인 함수는 memcpy입니다.
void * memcpy(
_Out_writes_bytes_all_(count) void *dest,
_In_reads_bytes_(count) const void *src,
size_t count
);
memcpy는 _Out_writes_bytes_all_
의 주석코드를 내부에서 사용하고 있는데, 이 주석의 의미는 _Out_
(_In_
과 유사합니다) + 지정된 바이트 수 만큼 데이터를 완전히 채울 것을 의미합니다.
지정된 바이트 수의 경우 memcpy에선 count가 되겠습니다.
SAL은 이처럼 프로그래밍 과정에서 발생하는 다양한 오류를 코드 분석을 통해 코드 안정성을 높이고 버그를 줄이는데 강력한 도움을 줄 수 있습니다.
SAL에 대한 자세한 내용은 MS공식문서를 통해 더 자세히 확인할 수 있습니다.
긴글 읽어주셔서 감사합니다.