Zero length array

C Programming 2008. 12. 3. 20:35
소스를 보다보니 이상한 (이라기보다 내가 여태 쉽게 접하지 못한) 코드를 발견하였다.

structure가 길이가 0인 배열을 가지고 있는 거다!!

sturct
{
    ...
    u_int8_t data[0];
    ...
};


음... 이게 무슨 용도인지 진짜 진짜 궁금해졌다.  그래서 확인해봤다.

#include <stdio.h>

int test1 (void)
{
    int a[0];
    int b;

    b = 2;

    printf ("%d 0x%X 0x%X %d\n", sizeof (a), &a, &b, a[0]);

    return 0;
}

int test2 (void)
{
    struct X
    {
        int a[0];
        int b;
    } x;
   
    x.b = 2;

    printf ("%d 0x%X 0x%X %d\n", sizeof (x), &x.a, &x.b, x.a[0]);

    return 0;
}

int test3 (void)
{
    struct X
    {
        char a[0];
        int b;
    } x;
   
    x.b = 0x12345678;

    printf ("%d 0x%X 0x%X %x %x %x %x\n", sizeof (x), &x.a, &x.b, x.a[0], x.a[1], x.a[2], x.a[3]);

    return 0;
}

int main (void)
{
    test1 ();
    test2 ();
    test3 ();

    return 0;
}


이것의 결과는 아래와 같다.

0 0x22CCB0 0x22CCAC 0
4 0x22CCC4 0x22CCC4 2
4 0x22CCC4 0x22CCC4 78 56 34 12


즉, 길이가 0인 배열은 일반 자동변수 그 자체로서는 아무 의미가 없지만, 구조체 내부에서는 나름대로 가변배열(variation length array)이 되는 것이다.  가변 배열이라고 하기에는 어차피 구조체의 크기만큼 이라는 제약 사항이 있기는 하지만 하나의 배열 요소로서 구조체의 모든 멤버를 접근하다는 그만큼 프로그램을 짤 때 유연성을 더해주는 요소가 되지 않을까 싶기도 하다. 

이전에 살짝 다뤘던 엔디안 체크도 이것으로 확인이 가능하겠다.
Posted by 강군님

댓글을 달아 주세요

예전에 짰던 지뢰찾기다... -.- 헥사도 짰던 걸로 기억하는데... 소스가 없다 걔는... -.-

Posted by 강군님

댓글을 달아 주세요

void GetFileInfo(LPSTR lpFileName, int *nIndex)
{
 SHFILEINFO sfi;

 int hIcon = SHGetFileInfo(lpFileName, DIRATTR, &sfi, sizeof(SHFILEINFO), 
        SHGFI_TYPENAME | SHGFI_SYSICONINDEX | SHGFI_ICONLOCATION); 
 *nIndex = sfi.iIcon;
 
 lpDesc=(TCHAR *)calloc(sizeof(TCHAR), 1024);
 strcpy(lpDesc, sfi.szTypeName);
}

 

사용자 정의 함수이고, lpFileName으로 들어온 파일이름(절대경로)을 시스템 이미지 리스트에 등록되어 있는 아이콘 인덱스를 찾아서

 

sfi 구조체의 iIcon 이라는 멤버에 값을 넣어주게 됩니다.  아래에 있는 lpDesc에서는 그 파일이 무슨 타입인지(디렉토리라든지 시스템 파일 이라든지 하는 문자열)를 저장하는 전역 변수고요, 사용한 곳에서 free() 시켜줍니다.

 

리스트 뷰의 프로시져에서 다음과 같이 시스템 이미지 리스트를 따옵니다.

 

s_hImageList= (HIMAGELIST)SHGetFileInfo("C:\\",0,&sfi,sizeof(SHFILEINFO),SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
l_hImageList= (HIMAGELIST)SHGetFileInfo("C:\\",0,&sfi,sizeof(SHFILEINFO),SHGFI_SYSICONINDEX | SHGFI_ICON);
SendMessage(hList, LVM_SETIMAGELIST, (WPARAM)LVSIL_SMALL, (LPARAM)s_hImageList);
SendMessage(hList, LVM_SETIMAGELIST, (WPARAM)LVSIL_NORMAL, (LPARAM)l_hImageList);

 

저는 리스트 뷰에서 구현했기 때문에 이렇게 했습니다.  이렇게 하면 시스템 이미지 리스트를 가져오게 됩니다.  첫번째는 작은 아이콘(16*16), 두번째는 노말한 아이콘(32*32)에 대한 리스트를 따오는 것이구요, 2개의 SendMessage()를 통해서 해당 리스트 뷰에 이미지 리스트를 등록합니다.  다음은 해당 디렉토리의 파일들을 검색하면서 정보를 따오는 부분이고요...

 

LI.mask = LVIF_TEXT | LVIF_IMAGE;

handle = FindFirstFile(fileFound, &ffdata);
 do
    {

      .........

         GetFileInfo(fullName, &iIcon);

         LI.iImage = iIcon;

      ........

         strcpy(LI.pszText, lpDesc);
         free(lpDesc);

    } while (FindNextFile(handle, &ffdata));
 FindClose(handle);

 

아까 정의했던 GetFileInfo를 사용해서 아이콘 인덱스를 가져오고, 해당 파일의 속성을 가져왔습니다.  당근 free() 하구요 :)

Posted by 강군님
TAG icon, Win32API

댓글을 달아 주세요

간만에 일찍 퇴근하고, 기타도 좀 뚱겨보고 책도 좀 들여다보고 티비를 보고 정신없이 웃기도 하다가 갑자기 옛날 네이버 블로그가 생각났다.  젠장... 이거 빨랑 없애버려야지... 좀 나중에 볼만한건 남겨놔야지... 하고 퍼온 것 중 첫번째...


#include <lm.h>

 

#pragma comment (lib,"netapi32.lib")

 

LPSTR GetWorkGroupName(void)

{

    static CHAR sGroup[256];

    

    memset(sGroup, 0x00, 256);

    

    if ( GetVersion() < 0x80000000)                

    {    // WinNT series

        const    DWORD    dwLevel = 102;

        LPSTR    pszServerName = NULL;

        BOOL    fIsDLLLoaded = FALSE;

 

        {

            WKSTA_INFO_102    *pBuf = NULL;

            NET_API_STATUS        nStatus;

 

            nStatus = NetWkstaGetInfo( pszServerName, dwLevel, (LPBYTE*)&pBuf );

 

            if (nStatus == NERR_Success)

            {

                //유니코드를 스트링으로 변환

                WideCharToMultiByte(CP_ACP, 0, (const unsigned short *)pBuf->wki102_langroup,

                            -1, (char *)sGroup, sizeof(sGroup), 0, 0);

            }

 

            if (pBuf != NULL) NetApiBufferFree(pBuf);

        }

    }

    else

    {

        // 9X에서는 레지스트리에서 검색을 해야함..

        LONG result;

        HKEY hKey;      

        DWORD dwType = REG_SZ;  

        DWORD dwSize = 128;

 

        result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\VxD\\VNETSUP",

                            0, KEY_READ, &hKey);

        if (result == ERROR_SUCCESS)

        {

            result = RegQueryValueEx(hKey, "Workgroup", 0, &dwType, (LPBYTE)sGroup, &dwSize);

        }

 

        hKey = NULL;

        RegCloseKey(hKey);

 

 //       int nLen = min(*pdwSize,_tcslen(szTempGroupName));

   //     _tcsncpy( szGroupName, szTempGroupName, nLen  );

     //   szGroupName[nLen] = 0;

       // *pdwSize = nLen;

    }

    return sGroup;

}

Posted by 강군님

댓글을 달아 주세요

endian이 전혀 문제 될 것이 없다고 생각했었는데, 자주 접하지 않으니 헷갈리기 시작했다. :( 이번 기회에 좀 확실히 해둘까.

#include <stdio.h>
#include <stddef.h>

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

    return 0;
}

이 상태에서 u.uc[0]의 값은 어떻게 들어가있을까?

전웅씨의 'C언어 펀더멘털'을 보면, 이렇게 정의되어 있다.

메모리의 주소가 낮은 바이트부터 높은 바이트 순으로 각 바이트를 읽는 것 : big endian
메모리의 주소가 높은 바이트부터 낮은 바이트 순으로 각 바이트를 읽는 것 : little endian

u.li는 endian에 상관 없이 당연히 최상위 비트부터 1번 비트까지는 0으로 채워지고, 0번 비트는 1로 되어 있을 것이다. 하지만 u.uc는 배열이므로 접근의 순서가 endian을 따르게 된다. 즉, little endian에서는 u.uc가 다음과 같이 정의되어 있을 것이다.

u.uc[0] = 0b00000001;
u.uc[1] = 0b00000000;
u.uc[2] = 0b00000000;
u.uc[3] = 0b00000000;

하지만 big endian의 경우 낮은 번지에서 높은 번지로 접근하게 되므로

u.uc[0] = 0b00000000;
u.uc[1] = 0b00000000;
u.uc[2] = 0b00000000;
u.uc[3] = 0b00000001;

간단한 듯 하면서도 헷갈리는 경우가 많은데, bit 단위의 연산이 잦은 프로그램일 경우 더욱 조심해야 할 것이며, 그에 앞서 이식성을 생각하고 코딩을 하는 것이 좋겠다.
Posted by 강군님
TAG c, endian

댓글을 달아 주세요

C에서 가변인자라 하면... 흔히들 생각하는 것은 va_list이다. printf ()등에서 흔히 사용되기 때문에... 익숙하기도 하지만 막상 구현하려고 하면 기억이 안나기도 하고... 신기하기도한 함수 -_-;
근데, 이거 말고도 가변인자 구현이 된다... 음... 왜 이걸 생각못했을까?

#include <stdio.h>

int add (int arg, ...);

int main (void)
{
  return printf ("sum is %d\n", add (5, 1, 2, 3, 4, 5));
}

int add (int arg, ...)
{
  int sum = 0, i;

  for (i = arg; i > 0; i--)
    sum += *(int *)(&arg + n);

  return sum;
}

음... 인자가 스택으로 들어온다는 것을 적절히 (?)활용한 예제이다. 위험도에 대해서는 좀 더 생각을 해봐야할 코드일 것 같은데, 어쨌든 간단히 구현하기는 좋은듯.
Posted by 강군님
TAG c, stack, va_arg

댓글을 달아 주세요