2010년 2월 19일 금요일

C++ Coding Conventions

version      : v0.6

최종수정일 : 2007.10.15

최종수정자 : 이주현

 

형상품목별 적용언어#

  • C++을 사용한다.

간격#

  • 프로그램에서 서로 다른 기능을 수행하는 블록이나 서브루틴 사이에는 1행 이상의 빈 줄을 삽입한다.
  • 각 블록이나 서브루틴은 적절한 탭 간격으로 들여쓰기를 하고, 블록의 open문과 closer 괄호는 열을 맞추어 프로그램의 이해와 식별을 쉽게 한다.
  • 하나의 탭은 공백 4칸에 맞도록 간격을 설정한다.

문자 사용의 규칙#

  • 소스 코드를 프린터로 출력할 때는 크기 9의 Courier New 폰트를 사용한다.
  • 기술자료 작성 및 규격화에 사용되는 워드프로세서는 한글로 하며, 문자는 굴림체, 크기는 11, 줄 간격은 180%, 문단 위 간격은 5(pt)로 한다. 기타 언급되지않은 사항은 별도의 기술자료 작성 지침서를 따른다.

파일 레이아웃#

  • 파일이름은 첫문자와 각 단어의 첫자는 대문자로 하며, 나머지는 소문자로 한다. ex) ClientSocket.h, ClientSocket.cpp
  • 각각의 소스 파일과 헤더 파일은 아래의 템플릿을 참고한다.

헤더 파일 레이아웃#

  • 인클루드 중복 방지용 #ifdef, #endif 문은 다음과 같이 작성한다.
  • 레이아웃은 아래의 예제와 같은 순서로 기입한다. 하지만, 필요에 따라 각각의 레이아웃에 다른 지정자를 넣거나 선언을 할 수 있다.
  • 아래 예제의 파일의 이름은 Header.h 이다. 주석에 대한 자세한 설명은 다음 장에 설명되어 있다.
  1. /**
     * @file  
     * @author  
     * @version     
     * @brief     
     *
     * @date       
     * @todo     
     */
    #ifndef _HEADER_H_
    #define _HEADER_H_
    /********************************** includes **********************************/

    /*********************************** defines **********************************/

    /********************************** typedefs **********************************/

    /***************************** class declarations *****************************/

    /****************************** extern variables ******************************/

    /*********************** inline function declarations *************************/

    /*************************** function declarations ****************************/


    #endif

소스 파일 레이아웃#

  • 소스 파일에 대한 레이아웃은 아래와 같다. 주석에 대한 자세한 설명은 다음 장에 설명되어 있다.
  1. /**
  2.  * @file  
  3.  * @author  
  4.  * @version  
  5.  * @brief        
  6.  *
  7.  * @date        
  8.  * @todo       
  9.  */
  10. /********************************** includes **********************************/
  11. /*********************************** defines **********************************/
  12. /********************************** typedefs **********************************/
  13. /****************************** global variables ******************************/
  14. /****************************** local variables *******************************/
  15. /***************************** class definitions ******************************/
  16. /**************************** function definitions ****************************/

 

주석에 대한 표준#

  • 기본적으로 doxygen 스타일을 준수한다.

    • @tag + [tab] + 내용 으로 서술한다.
    • 리스트 사용시 공백은 [tab]으로 구분을 하며, 한단계 하위로 내려갈 때 마다 [tab]을 추가한다.
  • 프로그램의 파일 의 주석

    • header 및 source 주석은 각 프로그램 파일의 시작 부분에 위치하며, 다음 사항을 포함한다. 볼드체는 반드시 기입해야 하는 내용이며, 나머지는 상황에 맞추어 추가/삭제 할 수 있다.

      • 파일명 : 현재 파일 명
      • 작성자 : 홍길동
      • 버전 번호 : V0.0(변경사항이 많거나 중요한 경우 소수점 앞의 정수를 1씩 증가시키고, 변경사항이 적거나 중요하지 않은 경우 소수점 뒤쪽의 값을 1씩 증가시킨다.)
      • 파일 설명 : 프로그램에 대한 요약 설명. 구성 모듈, 사용된 알고리즘, 가정, 제한사항, 부작용 등을 기록
      • 변경 이력 : 최초 파일 생성일자경 이력 : YYYY.MM.DD + [tab] + 수정자 이름 + [tab] + 간략한 수정 사항 기록
      • 해야 할 일 : 개선 사항이나 앞으로 추가되어야 할 내용을 기록한다.

 

  1. /**
     * @file       TBCodingConvention.h
     * @author     홍길동
     * @version   V0.1
     * @brief     파일에 대한 간략한 설명을 기술한다.
     *
     * 상세한 설명은 이곳부터 시작한다.
     *
     * @date      
     *   - 2007.10.13   이주현   알고리즘 수정
     *   - 2007.09.10   이주현   먼가를 수정하였음
     * @todo      
     *   - 유니코드에 대비할 것
     *   - 버그를 잡을 것
     */

 

 

  • 클래스에 대한 주석

    • 사용자가 개발한 클래스에 대한 주석은 클래스에 대한 기능을 설명하기 위해 작성되는 것으로서 모든 클래스에 적용되어야 한다. 클래스가 선언된 곳 바로 위에 사용한다. 볼드체 부분은 필수적으로 기입해야 하며, 그외의 항목은 선택적으로 기입한다.
    • 기술 순서는 다음과 같다.

      • friend 클래스
      • 클래스 내부에서 쓰이는 typedef
      • enum 타입 변수
      • public -> protected -> private 순으로 기술하며, 각각 내부에서는 attribute -> contructor & destructor -> operation 순으로 한다. attribute와 operation의 경우, instance 용을 먼저 기술하고 class 용을 나중에 기술한다.
    • 헤더 파일에서는 각 메쏘드에 대한 설명은 하지않고, 소스파일에서 자세히 기술한다.
    • public, protected, private 등의 지시자는 클래스 블럭({) 와 같은 레벨로 들여쓰기를 한다.

 

  1. /**
     * @brief     클래스에 대한 설명을 기술한다.
     *
     * 보다 자세한 설명을 기술한다.
  2.  * @todo
     */
    class CTBCodingConvention
    {
    /// friend 클래스
        friend class CFriendCodingConvention;
     
    /// typedef 타입은 언더스코어를 가지는 대문자이다.
        typedef unsigned int TB_BYTE;

  3. /// enum 타입, EState에 대한 간략 설명
        enum EState
        {
            STATE_APPROVED = 0,     ///< STATE_APPROVED 에 대한 설명
            STATE_REJECTED          ///< STATE_REJECTED 에 대한 설명
        };
     
    public:
    // Attributes 
        // 상수는 모두 대문자이며, 언더 스코어를 가지는 대문자를 사용한다.
        string strCodeName;
        static const char *BASE_NAME    ///< BASE_NAME 상수에 대한 설명

  4. // Constructor & Destructor
        CTBCodingConvention();
        ~CTBCodingConvention();
           
    // Methods
        // 멤버 함수는 대소문자를 섞어 쓰며 동사로 시작하며 첫문자는 소문자이다.
        void printTBStandard(void);
        // Get 또는 Set 멤버함수는 설정하거나 얻어오는 멤버 변수를 이름으로 사용하며, Get 또는 Set 키워드로 시작한다.
        void setNameOfStandard(string name);
        string getNameOfStandard(void);
        static int* getInstance();
    protected:
    // Attributes
       
    // Constructor & Destructor
        int nAccessibleByDerivedClasses   ///< 멤버 변수에 대한 설명
       
    // Methods
       
    private:
    // Attributes
        string strNameOfStandard          ///< 멤버 변수에 대한 설명
        CInfo* pBaseStandard;             ///< 간략한 설명
        static CTBCodingConvention *pInstance;    ///< 간략한 설명

  5. // Methods
        void setInternalHandler(CTBCodingConvention *t_variable);
    };

 

  • 함수에 대한 주석

    • 사용자가 개발한 Function에 대한 주석은 함수 기능을 설명하기 위해 작성되는 것으로서 모든 함수에 적용되어야 한다. 다음과 같은 정보들이 표현되어야 한다. 함수 바로 위 상단에 다음과 같은 사항을 기록한다. 볼드체로 된 항목은 필수적으로 기입해야 하며, 그 외의 항목은 선택적으로 기입한다. 단 인자가 없거나, 리턴 타입이 void일 경우는 생략할 수 있다.

      • 함수 설명 : 함수의 목적을 적는다. 필요한 경우 알고리즘의 설명을 기입한다.
      • 작성자 : 최종 개정한 사람의 이름을 적는다.
      • 최종 수정일 : 최종 개정한 날짜를 적는다.
      • 입력 데이터 : 입력되는 매개변수를 적고, 값의 범위가 중요한 경우 범위를 기입한다.

        • @param + [tab] + 인자이름 + [tab] + 인자에 대한 설명
      • 출력 데이터 : 반환 값의 간략한 설명을 적고, 값의 범위가 중요한 경우 범위를 기입한다.

        • @return + [tab] + 리턴타입(e.g. int, long, so on) + [tab] + 리턴 값에 대한 설명
    • 주석은 반드시 해당 함수 위에 기술되어야 하며, 빈 줄을 삽입하지 않는다.

 

  1. /**
     * @author     함수를 작성한 사람
     * @brief     함수에 대한 설명을 기술한다.
     * @param      name 이름에 대한 설명을 기술한다. 인자가 없다면 생략해도 된다.
     * @return     리턴하는 값에 대한 설명을 기술한다. 리턴하는 값이 없다면 생략해도 된다.
     * @exception  함수에서 발생할 수 있는 예외상황에 대해 기술한다.
     */
    void TBCondingStandard::SetNameOfStandard(string name)
    {
        // 함수의 바디
    }

 

  • 중요한 블록(Block)에 대한 주석

    • 프로그램에서 중요한 코드 블록들은 블록의 상단에 기능 설명을 하는 주석이 반드시 선행되어야 한다.
    • 함수 내부의 소스 코드에 수행하는 작업과 그 순서가 표현되도록 다음과 같이 주석을 작성한다.  형식은 '/// 숫자. 기술내용' 으로 구성된다.

 

  1. /// 1. XXX를 수행한다.
    ...
    /// 2. XXX를 수행한다.
    ...
    /// 3. XXX를 수행한다.
  2. ...

 

  • 라인(Line)에 대한 주석

    • Doxygen으로 파싱되길 원하지 않으면서, 프로그램의 설명이 필요하다고 판단되는 연산(Computation)문과 할당(Assignment)문에는 '//' (슬래시 두개) 주석을 넣는다.
    • 라인 주석은 하나의 라인 뒤에 위치하며 해당 라인의 행위나, 선언된 변수의 설명을 기입한다. 단, 실행문 뒤에 주석을 기입할 수 없는 경우는 실행문 위에 주석을 기입한다.
    • 선언된 변수 값의 범위가 중요할 경우 범위를 기입한다.

 

  1. int nId;           // The player id < MAX_PLAYER

    // 사격이라는 윈도우 화면을 달도록 메시지 전송
    TheApp.m_pMainWnd->SendMessage(WM_CLOSEFRAME, (unsigned int)"사격");
  2. SelectSides(nId);  // Choose partners and positions

 

  • 매크로에 대한 주석

    • 다음 세가지 중 한가지 방법을 택하여 주석을 단다.
  1. /// X와 Y 중 큰 값을 리턴하는 매크로
    #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))

    #define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) ///< X와 Y 중 큰 값을 리턴하는 매크로

    /// @brief X와 Y 중 큰 값을 리턴하는 매크로
    /// 두 인수를 같은 타입으로 줘야 안전할 것이다.
    #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))

 

  • 주석에 리스트 만들기

    • 칸을 맞추어 '-' 를 사용하면 된다. 여기서는 [tab]으로 들여쓰기를 맞춘다.
  1. /**
     * @brief    간단한 설명
     *
     * 자세한 설명은 이곳에서 부터 이다.
     *  - <b>10 11 12</b>
     *   모든 것이 순서대로 왔다. LastID는 매번 증가한다.
     *
     *  - <b>11 10 12</b>
     *    먼저 LastID가 11로 증가한다. 9->11로 변했으므로, 10의 값이 OmitList에
     *    추가된다. 다음으로 10이 오면 리스트에 존재하므로, 실행한다. 그리고
     *    리스트에서 데이터를 삭제한다. 12는... 정상적이므로 실행한다.
     *
     *  - <b>10 10 11</b>
     *    제일 처음 오는 10은 당연히 정상적으로 실행된다. 두번째로 오는 10은
     *    LastID값에 의해서 무시된다. 11은 다시 정상적으로 실행된다.
     */

 

명칭에 대한 표준#

  • 객체의 역할을 나타내는 Full Name의 표준 군사용어를 사용한다.
  • 언더바("_")로 시작되는 이름은 사용하지 않는다.  단, 단어 전체를 대문자로 표기하며 2개 이상의 단어를 조합하여 사용하는 경우 각 단어 사이에 밑줄(??_??)로 구분하여 사용한다.
  • 변수명

    • 변수의 명명은 '범위(전역일 경우에만 g_ 을 붙이고, 멤버 변수일 경우 m_을 붙인다.) + 접두사 + 설명적인 본체'로 이루어진다. 변수가 지역 변수인 경우의 명명은 범위를 생략한다.
    • 범위 : 변수의 전역 변수 여부를 나타낼 수 있도록 한다.

      • 예제 : 전역(g_), 멤버(m_)
    • 접두사 : 변수명에 그 변수의 타입을 나타내는 접두사를 붙여 표기하는 헝가리언 표기법을 사용한다.
    • 설명적인 본체

      • 첫글자는 대문자로 시작하며 나머지는 소문자를 사용한다. 두 단어 이상일 경우 각 단어의 첫 글자는 대문자로 쓴다.     g_iCountButton, m_pInstance
    • 포인터의 경우 p+[해당형 접두어]를 붙여 사용한다. m_piVar, m_pstrName
접두어 접두어의 의미
a 배열
b bool 형 변수
ch char 형 변수
uch unsigned char 형 변수
d double 형 변수
f float 형 변수
h handle 형 변수
l long 형 변수
p pointer 형 변수
pfn 함수 포인터
s short 형 변수
us unsigned short 형 변수
st 구조체 형 변수(객체)
str string 형 변수
sz NULL로 끝나는 문자열
i int 형 변수
ui unsigned int 형 변수
n 개수를 의미하는 int 형 변수
e enum 형 변수
c class 형 변수
un UNION 형 변수(객체)
pv void *
vec vector 형 변수
mtx mutex 형 변수
sem semaphore 형 변수
mq message queue 형 변수

 

  • 함수명

    • 첫글자는 소문자로 시작하며 단어의 시작은 대문자로 나머지는 소문자를 사용한다.

      • 단 윈도우용 프로그램을 작성할 때는 윈도우 API의 작명법을 따라, 함수를 대문자로 시작한다.
    • 동사 + 명사의 순서로 조합한다.      countBattalion()
  • 클래스명

    • 클래스를 대표할 수 있는 단어를 사용하고, 첫 문자는 대문자 'C'로 시작한다.
    • 클래스 객체의 변수명은 소문자 'c'로 시작하며, 두 단어 이상일 경우 각 단어의 첫 글자는 대문자로 쓴다.

 

  1. class CButton
    {
        ...
    };

    CButton cButtonMouse;

 

  • 상수명

    • 모두 대문자를 사용하며, 두 단어 이상일 경우 언더바("_")로 단어를 구분한다.
  1. MAX_NIFV

 

기타 코딩 스타일#

  • 기본 규칙

    • 하나의 행위는 하나의 라인으로 구성한다.
    • 대괄호('{}')를 이용하여 블록을 구성할 때는 새로운 줄에 블록을 기입한다.
  1. // 지양
    while (m_nCount > m_nLineLen) newLine();

    // 권장
    while (m_nCount > m_nLineLen)
    {
        newLine();
    }

 

  1. // 지양
    while (nCount > nLineLen) {
        if (m_nId>1) {
            m_nPlayer --;
        }
        else
  2.     {
            m_nPlayer ++;
        }
    }

    // 권장
    while (nCount>nLineLen)
    {
        if (nId>1)
        {
            nPlayer --;
        }
  3.     else
        {
            nPlayer ++;
        }
    }

 

  • 상수의 선언

    • 상수의 선언은 하나의 파일 또는 파일의 상단에 모아서 선언할 수 있도록 한다. 또한 이때 수직 정렬을 할 수 있도록 한다.
  1. #define PACKET_SIZE     20    ///< chars in message packet
    #define BUF_SIZE_MAX    256    ///< max allocatable space for buffer

 

  • 분기 문 작성

    • 분기 문의 등식에 상수를 사용할 때에는 반드시 상수를 왼편에 두어 '='가 빠졌을 때 발생할 수 있는 오류를 컴파일러가 찾을 수 있도록 한다. 또한 이는 찾고자 하는 값을 즉시 발견할 수 있도록 해준다.
  1. if ( 6 == nErrorNum )

 

  • 'if' 구문 작성

    • if 구문을 작성할 떄는 반드시 else 문을 이용하여 예외 처리를 할 수 있도록 한다. else 문에 내용이 없으면 주석을 사용하여 내용이 없음을 인지할 수 있도록 한다.
  1. if ( nId > i )
    {
        nPlayer --;
    }
  2. else
    {
        // do nothing
    }

 

  • 'switch' 문 작성

    • 각각의 case 문에는 break 이용하여 격리 시킬 것을 권장하며, default 문을 사용하여 예외처리를 한다.
    • case 의 경우 switch 지시자보다 한단계 낮은 레벨의 들여쓰기를 사용한다.
  1. switch ( nCount )
    {
        case NUM1:
            // do something
            break;
        case NUM2:
            // do something
            break;
        default:
            // do something
    }

 

  • 'goto' 문 작성

    • goto 문을 부득이 사용해야 하는 경우에는 반드시 그 목적과 사용범위를 명시한다.

 

관례#

  • C/C++ 은 하나의 문장을 아주 복잡하게 만들 수 있다. 이는 프로그램의 수행시간 단축, 사용 공간의 축소의 이득은 있으나, 가독성을 해친다. 따라서 복잡한 하나의 문장은 여러 개의 문장으로 분리해서 작성하길 권장한다.
  • 대입 연산자 사용

    • 하나의 문장에는 하나의 대입연산자 만을 사용한다. 여러 개의 대입연산자를 사용함으로써 가독성을 해치기 때문이다.
    • 분기 문의 등식/부등식 내에서는 대입연산자의 사용을 피한다.
  • 매개변수

    • 함수에 매개변수를 전달할 때는 연산자의 사용을 자제한다.
    • if, for, while 등의 조건절에서 연산자의 사용을 자제한다.
  1. // 지양
    plotPoint(mouse_x + prev_mouse_x * x_factor, mouse_y + prev_mouse_y * y_factor);

    // 권장
    new_x = mouse_x + prev_mouse_x * x_factor;
    new_y = mouse_y + prev_mouse_y * y_factor;
    plotPoint(new_x, new_y);

    // 지양
    if ( (mouse_x + prev_mouse_x * x_factor ) < max_x )
    {
        // do something
    }
       
    // 권장
    new_x = mouse_x + prev_mouse_x * x_factor;
    if ( new_x < max_x )
    {
        // do something
    }

 

  • 구조체 및 공용체

    • 구조체 및 공용체의 선언은 typedef 문을 사용한다.
    • 구조체 형식의 자료형은 St 를 접두어로 사용하고, 공용체 형식의 자료형은 Un을 사용한다.
    • 구조체의 객체명은 소문자 'st'를 접두사로 붙여서 사용한다.
    • 공용체의 경우 객체명은 소문자 'un'를 접두사로 붙여서 사용한다.
  1. typedef struct
  2. {
  3. char name[40];

  4. int age;

  5. dougle height;

  6. } StPerson;
  7. StPerson stP1

 

  • 열거형

    • 열거형의 명은 대문자 'E'를 접두사로 붙여서 사용한다.
    • 열거형의 객체명은 소문자 'e'를 접두사로 붙여서 사용한다.
  1. typedef enum
  2. {
  3. WHITE = 0,
  4. BLACK
  5. } EColor;
  6. EColor eColor1;

 

예제 파일 #

댓글 없음:

댓글 쓰기