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[] 도 가능합니다.
신고
Write your message and submit
Endian에 관한 문제는 embedded system에서는 항상 따라다니는 요소입니다.
 
little-endian에서는 제대로 돌아가는 프로그램이 big-endian에서는 오류를 일으키거나 하는 일은 다반사죠.
그래서 두가지 endian을 지원하기 위해 똑같은 테스트를 반복해서 하는 경우도 있죠.

보통은 매크로를 사용하여 빌드시 endian을 정하기도 하지만, runtime시 정할 수도 있습니다.

다음의 코드는 실행환경의 endian을 알아내는 코드입니다. (소스 수정 없이 두가지 endian을 테스트 할 수 있음을 의미합니다.)

#include "stdio.h"

int main(void)
{
    union
    {
        unsigned long int i;
        unsigned char uc[sizeof(long int)];
    }u = {1};

    if(u.uc[0] == 1) printf("little-endian");
    else if(u.uc[sizeof(long int)-1] == 1) printf("big-endian");
    else printf("unknown endian??");

    return 0;
} 

union은 잘사용되지 않는 자료형이지만 유용하게 사용되었네요.
신고
Write your message and submit
아래 코드의 실행 결과는 어떻게 될까요?
#include <stdio.h>
#include <string.h>
int main(void)
{
       int a = strlen("123");
       int b = strlen("123\0");
       int c = strlen("123\012");
       int d = strlen("123\0123\0ABC");
       int e = strlen("123\0ABC");
       int f = strlen("123\0123");
       int g = strlen("123\0""123");
       printf("a:%d, b:%d, c:%d, d:%d, e:%d, f:%d, g:%d\n", a, b, c, d, e, f, g);
       return 0;
}
지난번 삼중자와 마찬가지로 결과를 예측하기 쉽지 않습니다.

힌트 : vim에서 위 코드를 열어보세요.
신고
Write your message and submit
#include"stdio.h"
void main(void)
{
        printf("Hello? Is that you??!");
}

무척이나 간단해 보이는 소스코드입니다.

하지만, 프로그램의 결과를 정확하게 예측하기에는 보통의 내공을 가지고는 불가능합니다.
한번 도전해 보세요!!!

왜 그런지는 스스로 알아보세요! 정답은 제목에 있습니다.
신고
  1. Favicon of http://rudalson.tistory.com BlogIcon 없다캐라

    | 2014.06.26 14:08 신고 | PERMALINK | EDIT | REPLY |

    잘 모르겠습니다.
    예측한대로 결과가 나오는데요 ^^;;;;

    어떤점을 짚어봐야 되나요? 답이 궁금하네요

Write your message and submit