C 코딩 스타일 가이드 - 서식

반응형

본 문서는 소프트웨어 개발 시 준수해야 하는 코딩 스타일을 정의하고 가이드한다.

본 문서의 가이드는 C 언어를 대상으로 하고 있으며 C99 표준이 적용된다(추후 C11 등 최신 표준으로 변경 적용 가능하며, 이에 따라 본 문서의 내용이 일부 변경될 수 있다).

본 문서의 가이드는 구글 C++ 코딩 스타일 가이드(https://google.github.io/styleguide/cppguide.html)를 기반으로 내부적인 필요에 따라 일부 내용을 수정, 변경하여 적용한 것이다.

 

참고로 본 스타일 가이드에 기술된 대부분의 가이드 항목은 IDE나 편집기에 설정하여 자동 적용되도록 할 수 있다.

 

서식

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

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

 

 

줄 길이

F-1. 코드의 각 줄은 120 문자를 넘지 않게 한다.

 

문자 형식

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

 

들여쓰기

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

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

 

 

중괄호

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

// 함수 내용을 여는 중괄호와 닫는 중괄호는 모두 새로운 줄에 작성한다.
int Function(int a)
{
}

// 구조체 내용을 여는 중괄호와 닫는 중괄호는 모두 새로운 줄에 작성한다.
struct Structure 
{
};

// 열거형 내용을 여는 중괄호와 닫는 중괄호는 모두 새로운 줄에 작성한다.
enum eCode
{
};

// 조건문 내용을 묶는 중괄호는 같은 줄에 작성하고, 닫는 중괄호는 새로운 줄에 작성한다.
// 단, 가독성이 현저하게 낮은 경우 가독성 향상을 위해 묶는 중괄호를 새로운 줄에 작성할 수도 있다.
if (condition) {
  DoSomething();
}                                           

// switch 문을 묶는 중괄호는 같은 줄에 작성하고, 닫는 중괄호는 새로운 줄에 작성한다.
// 단, 가독성이 현저하게 낮은 경우 가독성 향상을 위해 묶는 중괄호를 새로운 줄에 작성할 수도 있다.
switch (var) {                                            
  case 0: 
    ...
}

 

F-5. 모든 조건문(if, switch)과 반복문(for, while)에서 중괄호를 반드시 사용한다. 본문이 한 줄인 경우에도 중괄호를 사용한다.

if (condition) {                                  
  DoSomething();
}                                           

while (condition) {
  DoSomething();
}

switch (var) {
  case 0:
    ...
}

 

 

강제 줄 바꿈

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

1) 일관성 있게 줄바꿈 한다.

2) 각 줄의 시작지점을 통일한다.

3) 보통 연산자 뒤에서 줄바꿈한다.

if ((this_one_thing > this_other_thing) &&
    (a_third_thing == a_fourth_thing) &&
    yet_another && 
    last_one) {
  ..
}

 

함수 선언과 정의

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

// 기본 형식
ReturnType FunctionName(Type var1, Type var2) 
{
  DoSomethong();  
}

// 한줄에 작성하지 못할 경우, 리턴 타입 작성 후 줄바꿈하여 작성한다.
ReturnType
ReallyLongFunctionName(Type var1, Type var2, Type var3) 
{
  DoSomething();  
}

// 리턴 타입을 제외한 함수이름, 인자만으로도 한줄에 작성하지 못할 경우, 리턴타입과 함수이름을 한줄에 작성하고, 각 인자를 서로 다른 줄에 작셩한다.
ReturnType ReallyLongLongLongLongLongFunctionName(
    Type var1,
    Type var2,
    Type var3)
{
  DoSomething();
}

 

주의 사항

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

함수 호출

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

// 기본 형식
bool retval = FunctionName(argument1, argument2, argument3);

// 같은 줄에 작성하지 못하는 경우, 첫번째 인자를 제외한 나머지 인자들을 별도의 줄에 작성한다.
// 인자의 시작위치는 통일한다.
bool retval = ReallyLongLongLongLongLongFunctionName(argument1,
                                                     argument2,
                                                     argument3);

 

주의 사항

  • 여는 괄호는 항상 함수 이름과 같은 줄에 작성한다.
  • 닫는 괄호는 항상 마지막 인자에 붙여서 작성한다.
  • 함수 이름과 여는 괄호 사이에는 스페이스를 넣지 않는다.
  • 괄호와 인자 사이에는 스페이스를 넣지 않는다.
  • 각 인자 사이에는 스페이스를 사용한다.
  • 모든 인자들은 가능한 한 정렬되어야 한다.
  • 인자들이 다음 줄로 이동할 경우 한 줄당 하나의 인자를 작성한다.
 

switch 문

F-9. case 구문은 스페이스 2개로 들여쓰기 한다.

F-10. case 구문의 본문은 스페이스 4개로 들여쓰기 한다.

F-11. 항상 default 구문을 포함해야 한다. default 케이스가 실행되지 말아야 할 경우 assert()하거나 사용자가 알 수 있도록 로그 출력 등을 수행해야 한다.

switch (var) {                                           
  case 0:                                          
    ..                                       
    break;

  case 1:
    ...
    break;

  default:
    assert(false);
}

 

 

반복문

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

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

 

리턴값

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

return result;  // 좋음 - 괄호 사용이 필요 없는 간단한 경우
return (some_long_condition &&  // 좋음 - 복잡한 표현식의 가독성을 높이는 경우 괄호가 허용됨.
        another_condition);              
return (value);  // 나쁨
return(result);  // 나쁨 

 

전처리기 지시자

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

// 좋음 - 지시자가 줄의 처음부터 시작한다.
#define NORMAL
if (lopsided_score) {
#if DISASTER_PENDING  // 좋음
  DropEverything();
#if NOTIFY  // 좋음
  NotifyClient();
#endif
#endif
  BackToNormal();
}

// 나쁨 - 지시자가 들여쓰기 되어 있다.
if (lopsided_score) {
  #if DISASTER_PENDING  // 나쁨
  DropEverything();
  #endif  // 나쁨
  BackToNormal();
}

 

F-15. 전처리기 지시자가 코드 블럭을 감싸고 있는 경우, 닫는 부분 "#endif" 뒤에는 여는 부분에 명시된 조건을 주석으로 표기한다.

if (lopsided_score) {
#if DISASTER_PENDING
  DropEverything();
#if NOTIFY          
  NotifyClient();
#endif  // NOTIFY
#endif  // DISASTER_PENDING
  BackToNormal();
}

 

 

가로 공백

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

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

 

가로 공백 - 일반 사항

F-17. 연속적으로 나열된 인자나 변수들을 구분하는 쉼표 "," 뒤에는 하나의 스페이스를 넣는다.
int i, j;
int x[] = { 0, 1, 2};
 
F-18. 모든 문장의 콜론 ":" 과 세미콜론 ";" 앞에는 스페이스를 넣지 않는다.
int i = 0;  // 모든 문장의 세미콜론 앞에는 스페이스를 사용하지 않는다.

switch (i) {
  case 3:  // switch 문의 case 구문의 콜론 앞에는 스페이스를 사용하지 않는다.
    ...
}

out:  // goto 문에서 사용되는 분기구문의 콜론 앞에는 스페이스를 사용하지 않는다.
  ...

 

F-19. 각 괄호 "(", ")" 와 괄호 안 내용 사이에는 스페이스를 넣지 않는다. 괄호 안 내용 자체는 가독성을 위해 스페이스를 사용할 수 있다.

int ret = Function(a, b);
int result = 1 + (a + b);
for (int i = 0; i < 5; ++i)

 

F-20. 중괄호 "{", "}" 를 이용한 리스트 초기화 시, 중괄호와 괄호 안 내용 사이에는 하나의 스페이스를 넣는다. 괄호 안 내용 자체도 가독성을 위해 스페이스를 사용할 수 있다.

int x[] = { 0, 1, 2 };   

 

 

가로 공백 - 반복문과 조건문 (if, else if, for, while)

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

// 나쁨
if(condition)
switch(var) 
while(condition)

 

F-22. 조건문/반복문에서 각 괄호 "(", ")" 와 조건구문/반복구문 사이에는 스페이스를 넣지 않는다.

switch (var)  // 좋음
switch ( var )  // 나쁨 
 
F-23. for 문에서 세미콜론 ";" 다음에는 하나의 스페이스를 넣는다.
for (int i = 0; i < 5; ++i) 
for (; i < 5; ++i)

 

가로 공백 - 연산자

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

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

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);  // 가독성을 위해 스페이스 생략 가능

 

F-25. 단항 연산자(예: -, ++, !) 와 그 인자 사이에는 스페이스를 넣지 않는다.

x = -5;             
++x;             
if (x && !y)

 

 

세로 공백

F-26. 세로 공백의 사용을 최소화한다.

꼭 필요한 경우가 아니면 빈 줄을 사용하지 않는다. 더 많은 코드가 화면에 들어올수록 프로그램의 흐름을 따라가거나 이해하기 쉽다.

단, 지나치게 조밀한 코드는 가독성을 저해하므로 적절한 수준을 유지해야 한다.

 

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

 

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

 

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

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

 

if 문

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

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

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

// 가독성을 위해 허용 가능한 형식
if (condition) {
}
// 주석….
else if (condition) {
}
// 주석 …
else {
}

 

기타

상식적이고 일관성있게 작성한다.

코드를 수정하는 경우 잠시 주변의 코드를 살펴 그것의 스타일을 판단하고, 해당 코드와 일관성을 가지도록 작성한다.

 

이 스타일 가이드를 따르지 않는 기존 코드와의 일관성을 유지하기 위해 본 가이드라인을 따르지 않을 수 있다.


 

파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있음

댓글

Designed by JB FACTORY