구글의 C++ 명명법을 알아봅시다. (참고 링크) 적당히 번역했습니다.

구글식 명명법을 알아둬야 나중에 구글갔을 때 명명법 갖고 싸우는 일이 없겠죠? 허허허.. 농담입니다.. 어짜피 요즘은 linter가 '어디어디 바꿔라' 잘 알려주지만 코드를 미리 네이밍 컨벤션에 맞게 작성하면 번거로이 수정할 일도 없겠죠.

STL 명명법과는 다릅니다.

 

 

일반 명명 규칙 (General Naming Rules)

다른 팀의 사람이 읽어도 이해가 쉬울 이름을 사용해 가독성을 최적화하세요.

오브젝트의 의도나 목적을 나타내는 이름을 사용하세요. 코드의 가로길이가 늘어나는 것을 무서워하지 마세요. 프로젝트를 모르는 사람이 모를법한 축약어(특히 두문자어)를 최소한으로 사용하세요. 단어 안의 글자를 지워 줄여쓰지 마세요. 경험상 위키피디아에 있는 축약어 정도는 괜찮습니다.

일반적으로, 이름의 설명 정도는 이름의 사용범위에 비례해야 합니다. 예를 들어, n은 5줄짜리 함수 내 변수명으로는 괜찮을 수 있지만, 클래스 범위에서 사용하기엔 너무 모호합니다.

// 좋은 예
class MyClass {
 public:
  int CountFooErrors(const std::vector<Foo>& foos) {
    int n = 0;  // Clear meaning given limited scope and context
    for (const auto& foo : foos) {
      ...
      ++n;
    }
    return n;
  }
  void DoSomethingImportant() {
    std::string fqdn = ...;  // Well-known abbreviation for Fully Qualified Domain Name
  }
 private:
  const int kMaxAllowedConnections = ...;  // Clear meaning within context
};
// 나쁜 예
class MyClass {
 public:
  int CountFooErrors(const std::vector<Foo>& foos) {
    int total_number_of_foo_errors = 0;  // Overly verbose given limited scope and context
    for (int foo_index = 0; foo_index < foos.size(); ++foo_index) {  // Use idiomatic `i`
      ...
      ++total_number_of_foo_errors;
    }
    return total_number_of_foo_errors;
  }
  void DoSomethingImportant() {
    int cstmr_id = ...;  // Deletes internal letters
  }
 private:
  const int kNum = ...;  // Unclear meaning within broad scope
};

널리 알려진 축약어는 괜찮다는 점을 알아두세요. (반복문의 i, 템플릿 매개변수의 T 등)

앞으로 얘기할 "단어"는 영어로 쓸 때 공백 없이 쓸 수 있는 것을 말합니다. 단어에는 축약어, 두문자어도 포함됩니다. 예를 들어 '단어' 첫 글자를 대문자로 써야하는 파스칼 케이스(Pascal case)를 사용할 때, StartRPC()가 아닌 StartRpc()와 같은 이름을 사용해야 합니다.

 

 

파일명 (File Names)

파일명은 모두 소문자로 써야 하고, 언더스코어(_) 또는 대시(-)를 포함할 수 있습니다. 프로젝트에서 사용하는 규칙을 따르세요. 딱히 규칙이 없으면 언더스코어(_)를 권장합니다.

아래는 사용 가능한 파일명의 예시입니다.

  • my_useful_class.cc
  • my-useful-class.cc
  • myusefulclass.cc
  • myusefulclass_test.cc // _unittest and _regtest are deprecated.

C++ 파일의 확장자는 .cc를 사용해야 하고, 헤더 파일은 .h를 사용해야 합니다. include할 때만 사용되는 파일은 inc 확장자를 가져야 합니다.

db.h처럼 /usr/include에 이미 존재하는 파일명을 사용하지 마세요

파일명을 구체적으로 작성하세요. 예를 들어, logs.h 대신 http_server_logs.h가 좋습니다. FooBar라는 클래스를 정의하는 파일명은 foo_bar.h, foo_bar.cc를 사용하세요.

 

 

타입명 (Type Names)

타입명은 대문자로 시작해야하고, 새 단어마다 대문자를 사용해야 합니다. 언더스코어는 사용하지 않습니다.
예시: MyExcitingClass, MyExcitingEnum

모든 타입(class, struct, type alias, enum, type template parameter)들의 이름은 동일한 명명법을 가져야 합니다.

// classes and structs
class UrlTable { ...
class UrlTableTester { ...
struct UrlTableProperties { ...

// typedefs
typedef hash_map<UrlTableProperties *, std::string> PropertiesMap;

// using aliases
using PropertiesMap = hash_map<UrlTableProperties *, std::string>;

// enums
enum UrlTableErrors { ...

 

 

변수명 (Variable Names)

변수의 이름(함수 파라미터 포함)과 멤버 변수들은 전부 소문자에, 단어 사이에는 언더스코어를 사용합니다. 클래스의 멤버 변수는 맨 뒤에 추가적으로 언더스코어를 사용합니다.
예시: a_local_variable, a_struct_data_member, a_class_data_member_

 

(1) 일반 변수명 (common variable names)

std::string table_name;  // OK - lowercase with underscore.
std::string tableName;   // Bad - mixed case.

 

(2) 클래스 멤버 변수 (class data members)

클래스의 static, non-static 멤버 변수는 일반 변수처럼 이름을 짓고, 맨 뒤에 언더스코어를 붙입니다.

class TableInfo {
  ...
 private:
  std::string table_name_;  // OK - underscore at end.
  static Pool<TableInfo>* pool_;  // OK.
};

 

(3) 구조체 멤버 변수 (struct data members)

일반 변수처럼 이름을 짓습니다. 맨 뒤에 언더스코어를 붙이지 않습니다.

struct UrlTableProperties {
  std::string name;
  int num_entries;
  static Pool<UrlTableProperties>* pool;
};

 

 

상수명 (Constant Names)

constexpr 또는 const로 선언되었고 프로그램 안에서 고정된 값을 가지는 상수 변수는 맨 앞에 k를 붙입니다. 대소문자로 구분할 수 없는 경우 드물지만 언더스코어를 사용할 수 있습니다.

const int kDaysInAWeek = 7;
const int kAndroid8_0_0 = 24;  // Android 8.0.0

static storage duration을 가진 변수는 모두 이 방식대로 명명되어야 합니다.

 

 

함수명 (Function Names)

일반 함수는 대문자로 시작하고 단어 시작마다 대문자를 사용합니다. 접근자(accessor), 변경자(mutator)는 변수처럼 이름지을 수 있습니다.

AddTableEntry()
DeleteUrl()
OpenFileOrDie()

접근자와 변경자(getter, setter)는 변수명처럼 이름을 붙일 수 있습니다. 예시: int count(), void set_count(int count)

 

 

네임스페이스명 (Namespace Names)

네임스페이스 이름은 모두 소문자여야 합니다. 최상위 네임스페이스는 프로젝트명을 따라야 합니다. 잘 알려진 최상위 네임스페이스와 중첩된 네임스페이스 사이 충돌을 피하세요.

최상위 네임스페이스의 이름은 보통 프로젝트나 팀 이름이 되어야 합니다. 그 네임스페이스 안에 있는 코드는 보통 그 프로젝트의 이름을 가진 폴더나 그 폴더의 하위 폴더에 배치되어야 합니다.

네임스페이스에 대해 축약된 이름에 대한 규칙이 변수명과 동일하게 적용되는 점을 참고하세요. 네임스페이스 안에 있는 코드는 네임스페이스를 쓸 일이 거의 없기 때문에, 축약된 이름을 쓸 필요도 없긴 합니다.

잘 알려진 최상위 네임스페이스와 겹치는 네임스페이스를 피하세요. 네임스페이스 사이의 충돌은 name lookup rule로 인한 빌드 실패를 야기할 수 있습니다. 특히, std 네임스페이스와 중첩된 네임스페이스를 만들지 마세요. 충돌이 나기 쉬운 이름(websearch::util)보다는 고유한 이름을 사용하세요(websearch::index, websearch::index_util)

내부 네임스페이스에 대해, 충돌을 일으키는 같은 내부 네임스페이스의 코드가 더해지는 걸 주의하세요. 그 때 내부용 이름을 고유하게 만들면 좋습니다 (ex. frobber.h에서 websearch::index::frobber_internal)

 

 

열거형 이름 (Enumerator Names)

열거형은 상수나 매크로처럼 이름붙어야 합니다: kEnumName, ENUM_NAME

되도록 상수 형태로 이름붙여야 하지만, 매크로처럼 이름 붙이는 것도 가능합니다. 열거형의 이름은 타입이므로, 타입명처럼 단어 첫글자를 대문자로 바꾸는 형식을 사용합니다: UrlTableErrors, AlternateUrlTableErrors

enum UrlTableErrors {
  kOk = 0,
  kErrorOutOfMemory,
  kErrorMalformedInput,
};
enum AlternateUrlTableErrors {
  OK = 0,
  OUT_OF_MEMORY = 1,
  MALFORMED_INPUT = 2,
};

2009년 1월까지 열거형을 이름붙일 때 매크로처럼 사용했지만 매크로와 열거형 사이 충돌을 야기했습니다. 따라서 상수 형태로 이름을 붙이도록 바뀌게 됐습니다. 가능하다면 새로운 코드는 상수 형태로 작성해야 합니다. 하지만, 옛날 코드는 컴파일 오류만 나지 않는다면 바꿀 이유는 없습니다.

 

 

매크로명 (Macro Names)

매크로는 대문자와 언더스코어를 사용합니다.
예시: MY_MACRO_THAT_SCARES_SMALL_CHILDREN_AND_ADULTS_ALIKE

일반적으로 매크로는 사용되면 안됩니다. 정말 필요할 때만 사용하세요.

#define ROUND(x) ...
#define PI_ROUNDED 3.0

 

 

명명법 예외 (Exceptions to Naming Rules)

C, C++ 표준에 존재하는것과 비슷한 것에 이름을 붙일 때는 기존 명명법을 따를 수 있습니다.

  • bigopen(): 함수명, open()의 형태를 따름
  • uint: typedef
  • bigpos: 구조체나 클래스, pos의 형태를 따름
  • sparse_hash_map: STL-like entity; STL의 명명법을 따름
  • LONGLONG_MAX: INT_MAX와 같은 상수

 

반응형