재미있는 C언어4. char pBuffer[1]의 역할은? 기록
2010.05.28 20:20 Edit
struct _BUFFER_INFO
{
BUFFER_MANAGER stBM;
pBuffer[1];
};
_BUFFER_INFO는 buffer cache의 전체정보를 담고 있는 자료구조로 크게 entry들을 관리하는 BUFFER_MANAGER와 실제 data가 저장되는 pBuffer로 나뉘어 있습니다. char pBuffer[1]를 유심히 살펴 보세요. 엥? 이건 무슨 코드인가요?
왜 char *pBuffer 라고 하지 않았을까요?
BUFFER_INFO는 buffer cache가 초기화 될 때 전체 메모리를 할당 받게 됩니다.
만약 char pBuffer[1]이 아닌 char* pBuffer였다면 BUFFER_INFO의 초기화는 이렇게 되었어야 합니다.
static PBUFFER_INFO g_pBI;
g_pBI = RtlAllocMem(sizeof(BUFFER_INFO));
IF (NULL == g_pBI)
{
NSD_CMZ((_T("g_pBI allocation fail, ERR[%d]"), err));
err = FERROR_INSUFFICIENT_MEMORY; break;
}
g_pBI->pBuffer = RtlAllocMem(BCACHE_SIZE);
IF (NULL == g_pBI->pBuffer)
{
NSD_CMZ((_T("g_pBI->pBuffer allocation fail, ERR[%d]"), err));
RtlFreeMem(g_pBI);
g_pBI = NULL;
err = FERROR_INSUFFICIENT_MEMORY;
break;
}
즉, BUFFER_INFO와 pBuffer의 메모리를 두번 할당 받아야 합니다. 물론 해제 할때도 마찬가지 입니다.
char pBuffer[1]이라면 어떻게 될까요?
static PBUFFER_INFO g_pBI;
g_pBI = RtlAllocMem(sizeof(BUFFER_INFO)+ BCACHE_SIZE);
IF (NULL == g_pBI)
{
NSD_CMZ((_T("g_pBI allocation fail, ERR[%d]"), err));
err = FERROR_INSUFFICIENT_MEMORY; break;
} 메모리 할당이 한번으로 끝났습니다.
중요한점은 BUFFER_INFO와 pbuffer가 메모리상으로 한덩어리로 잡힌다는 것입니다
이러한 접근은 메모리 할당을 두번에서 한번으로 줄인것 말고도 좋은 점이 있습니다
만약 이 BUFFER_INFO를 Log와 같이 File에 주기적으로 저장을 한다고 하면 어떨까요? char *pBuffer 로 사용했을 경우는 이 자료구조에 두번 접근해야 합니다. 필요없는 memcpy도 수반될 수 있습니다. 또한, BUFFER_INFO 와 pBuffer가 메모리 상으로 떨어져 있기 때문에 CPU에서 cache miss가 발생하는 확률도 높아집니다
char pBuffer[1]
별거아닌거 같지만, 코드도 짦아지고, 수행시간도 짧아질 수 있어 좋은 테크닉인 것 같습니다.
char pBuffer[0]도 의미는 유효하지만, C90표준에서는 허용하지 않고 있습니다. 일부 컴파일러는 경고나 에러를 낼 수도 있습니다.
ps. 하지만, 가독성은 좀 떨어지네요. ㅎㅎ
ps2. C99 표준에서는 가변길이 배열을 허용하고 있습니다. 즉, char pBuffer[] 도 가능합니다.
이 글과 관련된 글
- [2010/05/28] 재미있는 C언어7. 비운의 비트 필드 (3196)
- [2010/05/28] 재미있는 C언어5. printf 에서 생긴일 (2032)
- [2010/05/28] 재미있는 C언어3. 넌 어느 엔디안이니? (1627) *1
- [2009/08/28] 재미있는 C언어9. 64bit 시스템을 고려한 프로그래밍 (1673)
- [2009/06/16] 재미있는 C언어8. offsetof 매크로 (1849) *2
- Tag :
- 재미있는 C언어
