_countof 매크로
2011/03/15 06:48 |
Programming
_countof 매크로는 배열의 원소 개수를 돌려주는 서비스 매크로이다. 비주얼 스튜디오 2005 부터인가 제공되었던 것 같다.
StringCchCopy나 strcpy_s, wcscpy_s 같은 함수들을 사용할 때 편리하게 사용할 수 있다.
_countof 매크로는 다음과 같이 생겼다.
C언어를 사용할 때와 C++를 사용할 때의 구현이 다르게 되어있다.
C언어에서 사용되는 방식은 대부분의 사람들이 잘 알고 있는 방식일 것이며, C++에서는 템플릿을 이용해서 배열의 개수를 구하고 있다.
여기서 궁금해해야 할 점은
1번 질문의 답은 아래 블로그에 잘 설명이 되어있다.
C++ 템플릿으로 배열의 원소 개수를 구하는 방법
2번 질문의 답은 C 구현 방식에 약간의 문제가 있기 때문이다.
배열이 아니라 포인터일 경우에 C 방식은 제대로 개수를 구해주지 못한다.
그럼 템플릿 방식은 제대로 구해주냐 하면 물론 그럴수는 없다. 그래도 컴파일 에러를 내주기 때문에 좀 더 낫다. C 방식은 컴파일이 잘 되어버리며 잘못된 결과를 돌려준다.
아래 코드를 한번 보자. 설명을 쉽게 하기 위해 매크로 이름을 바꿨다.
여기서 배워야 할 점은,
StringCchCopy나 strcpy_s, wcscpy_s 같은 함수들을 사용할 때 편리하게 사용할 수 있다.
_countof 매크로는 다음과 같이 생겼다.
#if !defined(_countof)
#if !defined(__cplusplus)
#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))
#else
extern "C++"
{
template <typename T, size_t N>
char (*__countof_helper(UNALIGNED T (&_Array)[N]))[N];
#define _countof(_Array) (sizeof(*__countof_helper(_Array)) + 0)
}
#endif
#endif
#if !defined(__cplusplus)
#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))
#else
extern "C++"
{
template <typename T, size_t N>
char (*__countof_helper(UNALIGNED T (&_Array)[N]))[N];
#define _countof(_Array) (sizeof(*__countof_helper(_Array)) + 0)
}
#endif
#endif
C언어를 사용할 때와 C++를 사용할 때의 구현이 다르게 되어있다.
C언어에서 사용되는 방식은 대부분의 사람들이 잘 알고 있는 방식일 것이며, C++에서는 템플릿을 이용해서 배열의 개수를 구하고 있다.
여기서 궁금해해야 할 점은
- 템플릿을 통해 어떻게 배열의 원소의 개수를 구할 수 있는가.
- 도대체 왜 C와 C++을 전처리기를 사용해서까지 따로 구현했을까. 그냥 C 구현 하나만 쓰지.
1번 질문의 답은 아래 블로그에 잘 설명이 되어있다.
C++ 템플릿으로 배열의 원소 개수를 구하는 방법
2번 질문의 답은 C 구현 방식에 약간의 문제가 있기 때문이다.
배열이 아니라 포인터일 경우에 C 방식은 제대로 개수를 구해주지 못한다.
그럼 템플릿 방식은 제대로 구해주냐 하면 물론 그럴수는 없다. 그래도 컴파일 에러를 내주기 때문에 좀 더 낫다. C 방식은 컴파일이 잘 되어버리며 잘못된 결과를 돌려준다.
아래 코드를 한번 보자. 설명을 쉽게 하기 위해 매크로 이름을 바꿨다.
#define _countof_c(_Array) (sizeof(_Array) / sizeof(_Array[0]))
template <typename T, size_t N>
char (*__countof_helper(T (&_Array)[N]))[N];
#define _countof_cpp(_Array) (sizeof(*__countof_helper(_Array)) + 0)
void c_version(int* p) // int ar[] 과 같은 형식으로 넘어올 때도 마찬가지이다.
{
printf("%d\n", _countof_c(p));
}
void cpp_version(int* p)
{
printf("%d\n", _countof_cpp(p));
}
int _tmain(int argc, _TCHAR* argv[])
{
int a[100];
printf("%d\n", _countof_c(a)); // 100 올바른 결과
printf("%d\n", _countof_cpp(a)); // 100 올바른 결과
c_version(a); // 1 틀린 결과를 내어줘버렸다. 다행히 경고(C6384)는 발생한다.
cpp_version(a); // cpp_version함수는 컴파일이 안된다.
return 0;
}
template <typename T, size_t N>
char (*__countof_helper(T (&_Array)[N]))[N];
#define _countof_cpp(_Array) (sizeof(*__countof_helper(_Array)) + 0)
void c_version(int* p) // int ar[] 과 같은 형식으로 넘어올 때도 마찬가지이다.
{
printf("%d\n", _countof_c(p));
}
void cpp_version(int* p)
{
printf("%d\n", _countof_cpp(p));
}
int _tmain(int argc, _TCHAR* argv[])
{
int a[100];
printf("%d\n", _countof_c(a)); // 100 올바른 결과
printf("%d\n", _countof_cpp(a)); // 100 올바른 결과
c_version(a); // 1 틀린 결과를 내어줘버렸다. 다행히 경고(C6384)는 발생한다.
cpp_version(a); // cpp_version함수는 컴파일이 안된다.
return 0;
}
여기서 배워야 할 점은,
- C 방식 매크로를 쓸 때 언제 문제가 되는지를 알고 있어야 한다.
- C++를 사용함에도 불구하고 해당 매크로를 C방식으로 직접 만들어서 사용하는 경우를 보았다. 그냥 _countof를 사용한다.
- 마지막으로, 컴파일러 경고가 발생하면 무시하지 않는다.
'Programming' 카테고리의 다른 글
| 윈도우 드라이버를 만들 때 알아야 할 기초적인 내용들 (1) | 2011/05/23 |
|---|---|
| Duff's Device (0) | 2011/04/07 |
| _countof 매크로 (0) | 2011/03/15 |
| FIELD_OFFSET 매크로 (0) | 2011/03/01 |
| PAGED_CODE 매크로 (0) | 2011/02/27 |
| 디렉터리의 읽기 전용 속성 (4) | 2011/02/20 |

