'IT/일반'에 해당되는 글 3건

지금껏 Unix, linux용 프로그램만 작성하다가 회사를 옮긴 후 windows 프로그램을 하고 있다.
나에게 필요한 라이브러리들을 만들어서 사용하다가 이 곳에서도 그 프로그램을 이용하게 되었는데, 문제가 발생했다.

분명 나는 80byte만 쓰라고 fwrite()로 사이즈를 지정 했음에도 불구하고, windows에서는 81byte가 들어가 있었다.
이 문제를 찾느라 하루를 허비해버렸는데...

FILE *pFP;
int i, j;


pFP = fopen("test.txt", "w");

for( i = 1, j = 0;  i < 11;  i++, j++) {
    fwrite(&j, sizeof(int), 1, pFP);    // 0~9까지의 숫자를 쓰기
    fwrite(&i, sizeof(int), 1, pFP);    // 1~10까지의 숫자를 쓰기
}

fclose(pFP);

8byte를 10번 루프를 돌면서 작성을 하기 때문에 당연히 결과는 80byte만 작성이 되어야 함에도 불구하고, windows에서는 81byte가 엄연히 작성되어 있다.

그 이유는...
파일 종류 중에서 일반 바이너리 모드와 텍스트 모드와의 차이점은 개행문자('\n', Line Feed, LF)의 처리 방식 때문이였다.

Unix, Linux 등에서 개행문자 '\n'은 아스키코드10(0x0A)으로서 1문자 길이가 되지만, MS-DOS나 Windows 계통의 OS, 혹은 프린터라든지 기타 통신에 사용되는 텍스트에서의 개행은 CR(Carriage Return, 0x0D, '\r', 행리턴)과 LF를 연결해서 사용하므로 2byte가 된다.

그런 이유로 위 프로그램을 수행 후 생성된 파일을 Hex Code로 마지막을 보게 되면 0x0D, 0x0A 로 어처구니 1byte가 더 사용하게 되어 있음을 보게 되었다.
웃기는 건 fwrite() 함수 자체가 바이너리로 작성하게 되어 있는데, 그렇게 안 되니 참...
windows 시스템이 웃기는건지, 아님 그런 상황을 이해 못하는 내가 웃기는건지..

어쨌든, 해결 방법은 간단하다.
fopen 시 텍스트 모드가 아니라, 바이너리 모드로 옵션을 조정해줘야 한다.

pFP = fopen("test.txt", "wb");


'IT > 일반' 카테고리의 다른 글

Naming Rule for C/C++  (2) 2008.02.27
struct의 size 값은??  (0) 2008.02.22
블로그 이미지

쩐의시대

나답게 살아가고 나답게 살아가자

,

Naming Rule for C/C++

IT/일반 2008. 2. 27. 12:29
1. 개요
개발과 관련된 code convention과 naming rule에 대해 기술한다.

2. 필요성
  2-1. 소프트웨어 생명(Life Time)의 80%는 유지 / 보수에 소요된다.
  2-2. 소프트웨어의 가독성을 향상시킨다.
  2-3. 본래의 개발자에 의해서 소프트웨어 개발 전체가 유지되는 소프트웨어는 거의 존재하지 않는다.

3. 함수
  3-1. 기본 규칙
     * MainCategory_SubCategory1SubCategory2VerbObject1Object2
     * 예)
              - Log_OpenLogSystem() : modules/Log의 로그시스템 생성 함수
              - DB_TrieDBNew() : modules/DB/TrieDB의 생성 함수
  3-2. Verb 동사가 나오기 전까지는 카테고리를 표현
  3-3. Verb 동사는 어떤 기능을 하는지 표현
  3-4. Object는 특정 목적 대상이 있거나, 특별하게 구별하고 싶을 때
  3-5. 동사든 명사든 첫 글자는 대문자로 표기
  3-6. MainCategory가 첫 자가 대문자인 경우는 라이브러리(modules 디렉토리)에서, 소문자인 경우는 App 자체 (apps 디렉토리) 모듈
     * 예)
            - Pthread_Create() : 라이브러리(modules/Pthread)에 소속된 모듈로써, thread를 생성하는 함수
            - ppr_Create() : 라이브러리에 소속되지 않은 모듈로써 ppr 자료구조를 새롭게 생성하는 함수
            - static void _CheckLogFileSize() : _(언더바)로 시작하는 함수는 선언한 파일 안에서만 통용되는 함수로써 그 의미를 명확하게 하기 위해 static으로 선언.
  3-7. 다소 길어도 명확하게 - 의미 전달이 명확하게
  3-8. 생성자의 경우엔 "_Create", 소멸자인 경우엔 "_Destroy", 초기화의 경우엔 "_Init" 사용
      * 예) ppr_Create();, ppr_Destroy();, ppr_Init();
  3-9. File 쓰기엔 "_Write", 읽기엔 "_Read" 사용
  3-10. File read 시 첫번재 item 읽을때 "_ReadFirst", 그 다음 item 읽을때 "_ReadNext" 사용
      * 예) ppr_Write();, ppr_Read();, ppr_ReadFirst();, ppr_ReadNext();
  3-11. 구조체 object에 값 setting 할때 "_Put", 값 불러올때 "_Get" 사용
      * 예) Parameters_PutItem();, Parameters_GetItem();
  3-12. 통상적으로 사용하는 연산이 있는 경우는 그대로 사용한다.
      * 예) Queue_enQueue();, Queue_deQueue();, Stack_Push();, Stack_Pop();

4. 변수
  4-1. 헝가리안 표기법 사용
     *  헝가리안 표기법에 대한 분분한 의견이 있지만, C/C++에서 이만큼 의미를 명확히 표현해주는 표기법이 없다.
     * Format
       * x_xXxxxxxx
       * 0123456789
       * 0 : 변수의 위치를 지정한다. g(전역변수), m(멤버변수), 없음(지역변수)
       * 1 : 0 위치에 g 나 m을 지정한 경우 "_"를 기술
       * 2 : 자료형의 종류
       * 3 ~ : 변수의 의미있는 이름을 기술. 3 위치는 대문자를 사용, 변수 이름이 너무 긴 경우 자음만을 기술.
  4-2. Table



prefix type description example
b bool any boolean type bool bTrue;
c char character type char cLetter;
i int integer for index int iCars
n int number, quantity int nNum;
l long long type long lDistance;
u unsigned unsigned type(4byte) unsigned uPercent;
w WORD unsigned word(2byte) WORD wCnt;
dw DWORD unsigned double word(4byte) DWORD dwLength;
d double double floating point double dPercent;
f float floating point float fPercent;
s static a static variable static short ssChoice;
rg array stands for range float rgfTemp[16];
p * any pointer int iAddr;
sz * null terminated string of characters char szText[16];
pfn * function pointer int (*pifnFunc1)(int x, int y);
t struct a user defined type  
e enum variable which takes enumerated values  
E struct a user defined type  
g_ Global Global Variable String *g_psBuffer;
m_ Member class private member variable int m_iMember;
k constant formal parameter   void vFunc(const long klGalaxies)
r reference formal parameter   void vFunc(long &rlGalaxies)
str String string class(C++) String strName;
prg   dynamically allocated array char *prgGrades;
h handle handle to something hMenu
x/y   used as size int xWitdth, yHeight;

  4-3. Example
      * int g_nCnt;  : 정수형 글로벌 카운터
      * unsigned char ucByte;  : 한 바이트 데이터
      * char cChar;  : 한 문자
      * unsigned char rgucByte[10];  : 바이트 데이터 10개
      * char rgcChar[10];  : 문자 데이터 10개
      * char szChar[16 + 1]; : 문자 16개를 저장할 수 있는 문자열 공간
      * Etc
         * typedef로 재정의된 자료형일 경우 t_를 prefix로 사용
            * 예) unsigned char t_UC
      * Attention
         * 포인터(*) 및 참조(&)는 변수의 앞에 붙여서 선언
            * int * piAddr; -> int *piAddr;
      * Exception
         * 일반적으로 사용하는 변수 i, j, argc, argv는 그대로 사용한다.
         * C 라이브러리의 종속적인 변수 type일 경우, 일반적으로 사용하는 변수명을 사용한다.
           * 예)
              * phtread_t *tid (pthread_t가 unsigned int임에도 불구하구...)
              * phtread_attr_t *attr;

5.  구조체
  5-1. 기본 규칙
     * Maincategory_Name
  5-2. 첫 자만 대문자 (매크로와의 구분을 위해...)
  5-3. 예) Socket_Context (Socket의 Context에 사용되는 구조체)

6.  매크로
  6-1. 기본 규칙
     * MAINCATEGORY_SUBCATEGORY_NAME
  6-2. 대문자만을 사용
  6-3. 예) TKIR_INDEX_METHOD_BLOCK

7. 파일 생성규칙
  7-1. 하나의 디렉토리에 디렉토리를 대표하는 인터페이스용 헤더파일이 한 개 존재해야 함.
  7-2. 각각의 모듈 내부에서만 사용하는 함수를 인터페이스에 노출시킬 필요 없음.
  7-3. 헤더파일
      *. 중복 참조 방지용 매크로를 정의한다.

#ifndef __PTHREAD_H__
#define __PTHREAD_H__

#endif

  7-4. C++을 위하여 다음을 선언한다.
#ifdef __cplusplus
extern "C" {
#endif

#ifdef __cplusplus
}
#endif

8. 기타
  8-1. 리턴 값
     * 일반적으로
       * 0 : 성공
       * 음수 : 실패
       * 양수 : 오류는 아니지만, 기타 정보를 돌려줄 때
  8-2. 들여쓰기 (개인적인 취향에 따르도록)
     * 4칸이나 8칸. 경험상 4칸이 적절하나 개인적인 취향이니 적절히
  8-3. 칼럼 (개인적인 취향에 따르도록)
     * 될 수 있으면 80 칼럼을 지키는 것이 가독성 향상

9.  문서화
  9-1. 위키 (문서 작성)
     * 최소한 관련 모듈에 대해선 위키에 기본 내용이라도 작성한다.
  9-2. doxygen (documentation)
     * doxygen을 이용하여 문서화를 기본으로 한다.
     * 기본적인 format인

/**
@brief 함수 관련 설명
@param pArg1 첫 번째 함수 인자에 대한 설명
@param pArg2 두 번째 함수 인자에 대한 설명
@return
0 : success
-1 : fail
*/

이 형태를 유지하고, 나머지 format은 권고 사항이다.

     * 참조 URL : http://wiki.kldp.org/wiki.php/Doxygen

'IT > 일반' 카테고리의 다른 글

fwrite 함수로 작성했으나, linux와 windows에서 사이즈가 ...  (2) 2009.07.27
struct의 size 값은??  (0) 2008.02.22
블로그 이미지

쩐의시대

나답게 살아가고 나답게 살아가자

,

struct의 size 값은??

IT/일반 2008. 2. 22. 17:40

예전에 선배가 이런 류의 문제를 낸 적이 있다.
난 당당히 21Byte입니다. 라고 했었는데... 쩝...

아래 구조체를 sizeof 하면 얼마가 나올까?

 struct stStructSize {
      int            index;
      double         nFirstData;
      double         nLastData;
      unsigned char  chType;
  };

간단히 생각하면 21 byte가 나온다. ( 4 + 8 + 8 + 1 = 21 )
그렇지만 실제 sizeof(stStructSize)를 해보면 엉뚱하게도 32 byte 라는 결과를 출력한다.
왜 그런것일까? (참고로 int는 4byte, double은 8byte, unsigned char은 1byte)

이유은.. 컴파일러가 똑똑해서 그렇다.
사실 다소 메모리의 낭비가 있지만 원시코드로 변환했을때 효율적으로 퍼포먼스를 좋게하며 메모리를 관리(&접근) 하기 위함이다.
조금 더 얘기하자면 컴파일러의 내부 파싱이 dword aligned 을 기준으로 처리한 결과이다.
그래서 위의 경우에는 모든 자료형을 8byte로 계산한 것이다.

그렇지만 우리는 구조체의 접근방법, 데이터의 처리등 byte의 절대값으로 처리해야할 경우가 있다.
그럴때는 아래와 같이 전처리기를 선언해 주면 실제 원하는 크기인 21byte를 얻을 수 있다.

  #pragma pack(1)

그럼 아래처럼 확인해 보면 정확히 byte size를 얻을 수 있는것을 알 수 있다.

  int nLength = sizeof(stStructSize);
fprintf(stdout, "Struct Size = %d\n", nLength);

#pragma pack(1) 의 의미는 byte aligned 이다.
참고로 2는 word aligned 이며 4는 dword aligned 이다. classsizeof도 위와 마찬가지 결과이며 1을 생략한 #pragma pack() 으로 선언할 경우 기본적으로 dword aligned 처리된다.

위와 같은 문제아닌 문제가 있으므로 byte type 이나 word type을 이용할때는 주의가 필요하다.


한가지 더 퀴즈를 내자면,
int 형의 size를 알기 위해선 sizeof() 를 사용한다.
그러나, 이 sizeof()를 사용할 수 없을 경우 int 형의 size는 어떻게 알 수 있을까???







int  cTest = -1;
로 선언한 후 bit 연산을 하면 알 수 있다.

'IT > 일반' 카테고리의 다른 글

fwrite 함수로 작성했으나, linux와 windows에서 사이즈가 ...  (2) 2009.07.27
Naming Rule for C/C++  (2) 2008.02.27
블로그 이미지

쩐의시대

나답게 살아가고 나답게 살아가자

,