프로그래밍 언어/[ Coding Style Guide ]

[ Coding Style Guide ] 03. C언어 - 서식

kim.svadoz 2021. 1. 20. 17:37
반응형

서식

코딩 시 모두가 통일된 스타일을 사용하면 프로젝트를 파악하기 쉬워진다.

각자가 모든 서식 규칙에 동의하기 어렵고, 일부는 익숙해지는데 시간이 걸리지만, 프로젝트 구성원들이 규칙에 따라 코드를 작성함으로써 서로의 코드를 쉽게 이해하도록 하는 것은 중요하다

  • 줄 길이

    • 코드의 각 줄은 120 문자를 넘지 않게 한다.
  • 문자형식

    • 문자는 되도록 ASCII 문자를 사용하고, ASCII가 아닌 문자를 사용할 경우에는 UTF-8 형식을 사용한다.
  • 들여쓰기

    • 단계 당 2개의 스페이스로 들여쓰기(indentation) 하고 탭은 사용하지 않는다.

      코드 상의 그 어디에서도 탭을 사용하지 않는다.

  • 중괄호

    • 중괄호로 묶이는 모든 코드블럭에서, 각 중괄호 "{", "}"는 구문에 따라 같은 줄에 작성하거나 줄바꿈하여 작성한다.

      // 함수 내용을 여는 중괄호와 닫는 중괄호는 모두 새로운 줄에 작성한다.
      int Function(int a)
      {
      }
      
      // 구조체 내용을 여는 중괄호와 닫는 중괄호는 모두 새로운 줄에 작성한다.
      struct Structure
      {
      };
      
      // 열거형 내용을 여는 중괄호와 닫는 중괄호는 모두 새로운 줄에 작성한다.
      enum eCode
      {
      };
      
      // 조건문 내용을 묶는 중괄호는 같은 줄에 작성하고, 닫는 중괄호는 새로운 줄에 작성한다.
      // 단, 가독성이 현저하게 낮은 경우 가독성 향상을 위해 묶는 중괄호를 새로운줄에 작성할 수도 있다.
      if (condition) {
          DoSomething();
      }
      
      // switch 문을 묶는 중괄호는 같은 줄에 작성하고, 닫는 중괄호는 새로운 줄에 작성한다.
      // 단, 가독성이 현저하게 낮은 경우 가독성 향상을 위해 묶는 중괄호를 새로운줄에 작성할 수도 있다.
      switch (var) {
          case 0:
              ...
      }
    • 모든 조건문(if, switch)와 반복문(for, while)에서 중괄호를 반드시 사용한다. 본문이 한 줄인 경우에도 중괄호를 사용한다.

      if (condition) {
          DoSomething();
      }
      
      while (condition) {
          DoSomething();
      }
      
      switch (var) {
          case 0:
              ...
      }
  • 강제 줄 바꿈

    • 모든 조건문(if, switch), 반복문(for, while)의 표현식이 정해진 가로 줄 길이를 초과할 경우, 가독성 좋게 정렬하여 줄바꿈한다.

      1. 일관성 있게 줄바꿈 한다.
      2. 각 줄의 시작지점을 통일한다.
      3. 보통 연선자 뒤에서 줄바꿈한다.
      if ((this_one_thing) > this_other_thing) &&
          (a_third_thing == a_fourth_thing) &&
          yet_another &&
          last_one) {
          ..
      }
  • 함수 선언과 정의

    • 기본적으로 리턴 타입과 함수이름, 인자를 같은 줄에 작성하지만, 정해진 가로 줄 길이를 초과할 경우 줄바꿈하여 작성할 수 있다.

      // 기본 형식
      ReturnType FuctionName(Type var1, Type var2)
      {
          DomSomething();
      }
      
      // 한줄에 작성하지 못할 경우, 리턴 타입 작성 후 줄바꿈하여 작성한다.
      ReturnType
      ReallyLongFunctionName(Type var1, Type var2, Type var3)
      {
          DoSomething();
      }
      
      // 리턴 타입을 제외한 함수이름, 인자만으로도 한줄에 작성하지 못할 경우, 리턴타입과 함수이름을 한줄에 작성하고, 각 인자를 서로 다른 줄에 작성한다.
      ReturnType ReallyLongLongLongLongLongFunctionName(
          Type var1,
          Type var2,
          Type var3)
      {
          DoSomething();
      }
    • 주의사항

      • 여는 괄호 "("는 항상 함수 이름과 같은 줄에 작성한다.
      • 닫는 괄호 ")"는 항상 마지막 인자에 붙여서 작성한다.
      • 함수 일므과 여는 괄호 "(" 사이에는 스페이스를 넣지 않는다.
      • 여는 괄호 "(" 및 닫는 괄호 ")"와 인자 사이에는 스페이스를 넣지 않는다.
      • 각 인자 사이에는 쉼표 + 하나의 스페이스를 사용하여 구분한다.
      • 여는 중괄호 "{" 는 항상 닫는 괄호 ")" 다음 줄에 작성한다.
      • 닫는 중괄호 "}"는 혼자 마지막 줄에 위치해야 한다.
      • 모든 인자는 이름을 가져야 하며, 선언과 구현에서 같은 이름을 가져야 한다.
      • 함수 내 기본 들여쓰기는 2개의 스페이스다.
      • 모든 인자들은 가능한 한 정렬되어야 한다.
      • 인자들이 다음 줄로 이동할 경우 2개의 스페이스 들여쓰기를 사용한다.
      • 인자들이 다음 줄로 이동할 경우 한 줄당 하나의 인자만 작성한다.
  • 함수 호출

    • 기본적으로 한 줄로 작성하지만, 정해진 가로 줄 길이를 초과할 경우 줄바꿈하여 작성할 수 있다.

      // 기본 형식
      bool retval = FunctionName(argument1, argument2, argument3);
      
      // 같은 줄에 작성하지 못하는 경우, 첫 번째 인자를 제외한 나머지 인자들을 별도의 줄에 작성한다.
      // 인자의 시작위치는 동일하다.
      bool retval = ReallyLongLongLongLongLongFuctionName(argument1,
                                                          argument2,
                                                          argument3);
  • switch문

    • case 구문은 스페이스 2개로 들여쓰기 한다.
    • case 구문의 본문은 스페이스 4개로 들여쓰기 한다.
    • 항상 default 구문을 포함해야 한다, default 케이스가 실행되지 말아야 할 경우 assert()하거나 사용자가 알 수 있도록 로그 출력 등을 수행해야 한다.
    switch (var) {
        case 0:
            ...
            break;
    
        case 1:
            ...
            break;
    
        default:
            assert(false);
    }
  • 반복문

    • 비어 있는 반복문은 세미콜론 ";"대신 중괄호 "{}"를 사용하고, 중괄호는 조건문 다음에 붙여서 작성한다.

      for (int i = 0; i < kSomeNumber; ++i) {}
      while (condition); // 나쁨
      while (condition) {} // 좋음
  • 리턴값

    • return 표현식을 불필요하게 괄호로 묶지 않는다.

      return result;    // 좋음 - 괄호 사용이 필요 없는 간단한 경우
      return (some_long_condtion && another condition);    // 좋음 - 복잡한 표현식의 가독성을 높이는 경우 괄호가 허용됨.
      return (value);    // 나쁨
      return(result);    // 나쁨
  • 전처리기 지시자

    • 전처리기 지시자의 "#" 기호는 항상 그 줄의 처음에 작성한다. (들여쓰기 된 코드의 내부의 전치리기 지시자 포함)

      // 좋음 - 지시자가 줄의 처음부터 시작한다.
      #define NORMAL
      if (lopsided_score) {
      #if DISATER_PENDING    // 좋음
          DropEverthing();
      #if NOTIFY // 좋음
          NotifyClient();
      #endif
      #endif
          BackToNormal();
      }
      
      // 나쁨 - 지시자가 들여쓰기 되어 있다.
      if (lopsided_score) {
          #if DISASTER_PENDING // 나쁨
          DropEverything();
          #endif // 나븜
          BackToNormal();
      }
    • 전처리기 지시자가 코드블럭을 감싸고 있는 경우, 닫는 부분 "#endif" 뒤에는 여는 부분에 명시된 조건을 주석으로 표시한다.

      if (lopsided_score) {
      #if DISASTER_PENDING
          DropEverything();
      #if NOTIFY
          NotifyClient();
      #endif // NOTIFY
      #endif // DISASTER_PENDING
          BackToNormal();
      }
  • 가로 공백

    • 줄 끝에는 공백 문자를 사용하지 않는다.

      줄 끝에 공백문자를 두면 같은 파일을 편집하는 다른 사람이 기존의 뒤쪽 공백문자를 삭제할 경우, 코드 내용의 변경이 없이도 코드변경이 발생한다.

  • 가로 공백 - 일반사항

    • 연속적으로 나열된 인자나 변수들을 구분하는 쉼표 ","뒤에는 하나의 스페이스를 넣는다.

      int i, j;
      int x[] = { 0, 1, 2};
    • 모든 문장의 콜론 ":"과 세미콜론 ";" 앞에는 스페이스를 넣지 않는다.

      int i = 0;    // 모든 문장의 세미콜론 앞에는 스페이스를 사용하지 않는다.
      
      switch (i) {
          case 3:    // switch 문의 case 구문의 콜론 앞에는 스페이스를 사용하지 않는다.
              ...
      }
      
      out:    // goto 문에서 사용되는 분기구문의 콜론 앞에는 스페이스를 사용하지 않는다.
    • 각 괄호 "(", ")"와 괄호 안 내용 사이에는 스페이스를 넣지 않는다. 괄호 안 내용 자체는 가독성을 위해 스페이스를 사용할 수 있다.

      int ret - Fuction(a, b);
      int result = 1 + (a + b);
      for (int i = 0; i < 5; ++i)
    • 중괄호 "{", "}"를 이용한 리스트 초기화 시, 중괄호와 괄호 안 내용 사이에는 하나의 스페이스를 넣는다. 괄호 안 내용 자체도 가독성을 위해 스페이스를 사용할 수 있다.

      int x[] = { 0, 1, 2 };
  • 가로 공백 - 반복문과 조건문(if, else, if, for, while)

    • 조건문/반복문의 키워드(if, else, if, switch, for, while)와 여는 괄호 "(" 사이에는 하나의 스페이스를 넣는다.

      // 좋음
      if (condition)
      switch (var)
      while (condition)
    • 조건문/반복문에서 갈 괄호 "(", ")"와 조건구문/반복구문 사이에는 스페이스를 넣지 않는다.

      // 좋음
      switch (var)
    • for문에서 세미콜론 ";"다음에는 하나의 스페이스를 넣는다.

      for (int i = 0; i < 5; ++i)
      for (; i < 5; ++i)
  • 가로 공백 - 연산자

    • 연산자(=, +, -, /, %, >>, <<, ^, &, |) 전후에는 각각 하나의 스페이싀를 넣는다.

      하지만 가독성을 위해서 각 항마다 스페이스를 넣지 않을 수 도 있다.

      a = (w * y) + (t / z) - 1;
      a += 3;
      a = b >> 3;
      a = b ^ 2;
      a = y | 3;
      a = z & 3;
      a = (w*y) + (t+z);    // 가독성을 위해 스페이스 생략 가능
    • 단항 연산자(예, -, ++, !)와 그 인자 사이에는 스페이스를 넣지 않는다.

      x = -5;
      ++x;
      if (x && !y)
  • 세로 공백

    • 세로 공백의 사용을 최소화 한다.

      꼭 필요한 경우가 아니면 빈 줄을 사용하지 않는다. 더 많은 코드가 화면에 들어올수록 프로그램의 흐름을 따라가거나 이해하기 쉽다. 단, 지나치게 조밀한 코드는 가독성을 저해하므로 적절한 수준을 유지해야 한다.

    • 함수 사이에 3개 이상의 빈 줄을 추가하지 않는다.

    • 함수의 시작이나 끝 부분에 빈 줄을 사용하지 않는다.

    • 함수 내부에서도 빈 줄을 되도록 사용하지 않는다.

      단, 가독성 향상을 위해 블록 별로 빈 줄을 구분 할 수도 있다.

  • if문

    • else if 또는 else 문은 이전 if문 또는 else if 문을 닫는 중괄호와 같은 줄에 작성한다

      필요한 경우 가독성을 위해 이전 중괄호의 다음줄에 작성할 수 도 있다.

      // 기본 형식
      if (condition) {
      } else if (condition) {
      } else {
      }
반응형