minzkn의 코딩규칙

대문 / 공개프로젝트 / minzkn의 코딩규칙

minzkn의 코딩규칙

  • 작성자
    조재혁(Mminzkn@minzkn.com)

  • 고친과정
    2005년 7월 22일 : 처음씀
    2010년 10월 21일 : 규칙개정

1.1. C/C++

  • 규칙의 관점 (본 규칙을 작성하는데 기준이 되는 사항)
    1. 헝가리안 표기법같이 대소문자 혼합표기규칙은 Shift키의 접근이 매우 빈번하다는 점에서 불편하다고 생각되어 대문자는 되도록 사용하지 않도록 정의
    2. 헝가리안 표기법같이 변수명에 타입이 명시되는 규칙은 어느정도 도움이 되기는 하지만 그것보다는 재진입성 여부를 판별하도록 하여 경쟁조건등에 보다 신경쓰는 방향으로 선택하도록 정의
    3. 코드의 호환성을 최대한 높이기 위해서 다양한 문법의 허용보다는 제한적이지만 과거부터 호환되어온 표준을 좀더 비중있게 사용하도록 정의
    4. 편집기마다 달라질수 있는 View의 다양성을 고려하여 모든 View에서 동일한 모양이 나오기 위한 사항을 정의
    5. C언어의 간결함의 특징을 활용하기 보다는 재사용성이 높은 코드를 생성하기 위한 심볼규칙 정의

  • 들여쓰기
    1. TAB은 되도록이면 들여쓰기에 사용하지 않는다. (소스편집기 및 사용자마다 선호하는 TAB size가 다르기 때문)
    2. 한번의 들여쓰기는 4칸의 Space(0x20)로 사용한다.

  • 주석
    1. 해당 소스가 C++에서만 사용할것이 아니라면 C++의 주석인 "//"는 절대로 사용하지 않는다. (ISO C99에서는 이것이 C에서도 정식으로 채택되었으나 ISO C89이하 표준을 지키는것이 컴파일러 호환성에서 좋다고 생각됨)
    2. C의 주석인 "/* ... */" 만을 사용
    3. 내포된 주석형태 "/* ... /* ...?... */ ... */"와 같은 형태의 주석은 사용을 금지한다.

  • typedef의 선언
    1. typedef에 의해서 선언된 심볼은 모두 앞에는 "__"를 붙이고 뒤에는 "_t"를 붙인다.
    2. typedef에 의해서 선언된 심볼은 반드시 앞에 "__"를 붙이지 않은 define을 함께 정의한다.
    3. 즉, 다음과 같은 형태로 선언을 한다.
      #if !defined(my_int_t)
      typedef int __my_int_t;
      # define my_int_t __myint_t
      #endif
      
    4. 이렇게 typedef와 define이 함께 사용되어 선언되면 다음과 같이 코드상에서 해당 type이 선언되어 있는 경우와 아닌 경우 구현을 달리할수 있기 때문이다.
      #if defined(my_int_t)
      my_int_t value;
      #else
      signed int value;
      #endif
      


  • 공용체 및 구조체 선언
    1. 되도록이면 멤버변수는 앞에 "m_"를 붙인다.
    2. typedef 선언과 함께 선언한다.
      #if !defined(my_interface_t)
      typedef struct my_interface_ts {
          int m_member_value;
      }__my_interface_t;
      # define my_interface_t __my_interface_t
      #endif
      
    3. Library의 Header로 배포되어 사용되는 경우 반드시 구조체 Align을 지정한다. 이것은 Library빌드환경과 배포환경에서의 빌드환경에서 컴파일러의 Align기본값이 다른 경우 발생하는 문제의 소지를 막을수 있다.
      #if !defined(my_interface_t)
      # pragma pack(push,8)
      typedef struct my_interface_ts {
          int m_member_value;
      }__my_interface_t;
      # define my_interface_t __my_interface_t
      # pragma pack(pop)
      #endif
      


  • 재진입이 불가능한 변수의 선언
    1. 전역변수와 같이 재진입이 불가능한 변수는 Global의 의미를 갖는 "g_" 를 prefix로 사용한다.
      int g_argc;
      
      int main(int_s_argc, char **s_argv)
      {
          g_argc = s_argc;
      }
      


  • 재진입이 가능한 변수의 선언
    1. 지역변수와 같이 재진입이 가능한 변수는 Stack의 의미를 갖는 "s_" 를 prefix로 사용한다.
      int main(void)
      {
          int s_exit_code = EXIT_SUCCESS;
      
          return(s_exit_code);
      }
      
    2. 만약 static 으로 선언하였는제 이를 변경하지 않는것이 확실하고 함수내에서 지역적으로 이용되는 경우는 다음과 같이 표기할수 있다.
      int main(void)
      {
          static char sg_welcome[] = {"Hello world"};
      
          (void)fprintf(stdout, "%s", (char *)(&sg_welcome[0]));
      
          return(EXIT_SUCCESS);
      }
      


  • 값의 변경이 허용되지 않는 변수의 선언
    1. const 형과 같이 1회만 초기화가 가능한 변수는 Constant value의 의미를 갖는 "c_" 를 prefix로 사용한다.
      int main(void)
      {
          const int c_exit_code = EXIT_SUCCESS;
          static char cg_welcome[] = {"Hello world"};
      
          (void)fprintf(stdout, "%s", (const char *)(&cg_welcome[0]));
      
          return(c_exit_code);
      }
      


  • 외부참조를 원하지 않는 심볼의 선언
    1. extern 선언과 같이 외부 참조를 허용하는 경우가 아닌 static 전역심볼선언의 경우 앞에 "__"를 붙여서 이를 명확히 의사를 표현한다.
      #define __def_default_private_key (0x12345678)
      static int __g_private_key = __def_default_private_key;
      


  • goto label의 선언
    1. 성능상 유리하고 코드가 간결한 경우에만 goto 구문을 사용하는것으로 제한한다.
    2. label은 앞에 "_l"(소문자 L) 를 붙이며 들여쓰기는 하지 않는다.
      int io_control(int s_ioport)
      {
          if(s_ioport == (-1)) {
              goto l_return;
          }
      
          /* ... */   
      
      l_return:;
          return(0);
      }
      


  • Macro의 선언
    1. 모든 매크로는 "def_" 를 prefix로 사용한다. 그리고 괄호로 감쌀수 있는 값의 경우는 항상 관호로 감싸준다. 특히 수식의 경우는 반드시 괄호로 둘러싸서 연산자 우선순위에 따른 문제를 봉쇄한다.
      #define def_default_buffer_size (32 << 10)
      


  • 함수명의 결정
    1. 모든 함수는 name space를 신중히 고려하여 결정하며 해당 모듈명을 반드시 prefix로 사용한다.
      /* 모듈명이 "mzapi"라고 한다면 */
      void mzapi_hello_world(void)
      {
          (void)fprintf(stdout, "Hello world\n");
      }
      
    2. 반드시 name space 를 고려하여 변수명을 결정해야 한다. get_byte, TRUE, FALSE, ERROR, debug 같은 함수명이나 매크로명을 절대로 사용하지 않는것을 원칙으로 해야 하는데 이러한 변수명의 사용은 재사용성을 떨어뜨리는 결정적인 요인중에 하나이기 때문이다.
  • 완전한 형변환자의 사용
    1. 특별히 애매한 경우가 아니라면 명확한 Casting을 꼭 해준다.
      int example_puts(const char *s_string)
      {
          return(fprintf(stdout, "%s", s_string));
      }
      
      int main(void)
      {
          char const c_const_string[] = {"Hello world !\n"};
      
          (void)example_puts((const char *)(&c_const_string[0]));
      
          return(0);
      }
      


  • 함수의 원형와 프로토타입을 명확히 분리하며 extern구문을 정확히 사용한다.
    1. 함수의 원형이 선언되면 반드시 프로토타입을 선언한다.
    2. 외부참조인 경우 extern 구문을 반드시 표시한다.
      /* header.h */
      extern int example_info(void); /* 함수의 외부참조 선언 */
      
      /* source.h */
      int example_info(void); /* 함수의 프로토타입 선언 */
      
      int example_info(void)
      {
          /* ... */
      
          return(0);
      }
      


  • 대괄호 규칙
    1. 일반 함수는 open과 close가 같은 칸에 맞춘다.
      void my_function(void)
      { /* open */
      } /* close */
      
    2. 함수나 조건문등 함수를 제외한 나머지 모든 open과 close는 open이 해당 조건문의 뒤에 오고 close는 해당 조건문의 첫 칸에 맞춘다.
      if (my_expression == 0) { /* open */
      } /* close */
      for(;;) {
      }
      do {
      }while(0);
      switch (case) {
          case:
              break;
          default:
              break;
      }
      


  • 대소문자의 사용
    1. 심볼에 되도록이면 대문자를 사용하지 않는다. (대소문자를 혼용하여 사용하므로써 얻어지는 이득보다 심볼예측성에서 혼란이 더 크다고 생각되므로 되도록이면 소문자만 사용한다.)

  • 상수를 비-상수로 변환하고자 할때는 형변환 캐스팅으로 해결하지 않고 공용체를 통해서 해결한다.
    /* 이 예제의 경우 함수내에서 포인터의 변형이 일어나지는 않지만 반환받는 곳에서는 const로 받지 않는 경우를 제시한것이다. */
    char *never_null_string(const char *s_string, const char *s_default_string)
    {
        union {
            char *m_string;
            const char *m_const_string;
        }s_complex_string;
    
        if(s_string == ((const char *)0)) {
            s_complex_string.m_const_string = s_default_string;
        }
        else {
            s_complex_string.m_const_string = s_string;
        }
        
        return(s_complex_string.m_string);
    }
    


  • 가급적 함수 인자의 개수는 5개 이하로 제한
    • 일부 아키텍쳐의 경우 함수 인자를 제한된 개수의 Scratch register 를 통해서 전달할 수 있으며 이를 고려한다면 인자를 5개 이하로 함수 설계를 하도록 한다.

1.2. Assembly

  • 들여쓰기
    1. TAB은 되도록이면 들여쓰기에 사용하지 않는다. (소스편집기 및 사용자마다 선호하는 TAB size가 다르기 때문)
    2. 한번의 들여쓰기는 4칸의 Space(0x20)로 사용한다.
    3. 제어구문은 들여쓰기를 되도록이면 하지 않고 OPCODE에 해당하는 명령들만 한번의 들여쓰기를 한다.

  • 대소문자
    1. 되도록이면 소문자로 통일한다.
Retrieved from https://www.minzkn.com:443/moniwiki/wiki.php/mzCodingRules
last modified 2024-05-17 23:26:16