07
08
728x90

**참고: https://google.github.io/styleguide/cppguide.html#Variable_Names

위의 C++스타일 가이드를 바탕으로 작성, 번역했으며, 필요에 따라 해당 포스트는 내용이 추가되거나 삭제될 수 있습니다.

개인적으로 추가하고 싶은 내용은 괄호 안에 추가라고 적고 추가했습니다.

영어도 잘 못하고 C++도 잘 못다뤄서 어색하거나 모호한 부분은 영문표기를 추가 하겠습니다. 외에 이상한거 있으면 댓글로 알려주세요

 


네이밍

일관성을 지킬 수 있는 규칭중 가장 중요한 것이 이름을 짓는것이다. 이름이 어떻게 생겼는지만 봐도 이게 어떤종류인지 알 수 있게 해준다. 그러면 이게 변수인지 함수인지 상수인지 매크로인지 등 선언부로 찾아가서 확인하지 않아도 된다.

 

네이밍 규칙은 사실 짓는 사람 맘대로지만 여러 사람이 일관성있게 이름을 짓는것이 좋기에 해당 문서를 바탕으로 포스팅한다.


일반적인 네이밍 규칙

다른 팀에 있는 사람들도 알아볼 수 있는 명확한 이름을 사용해 가독성을 높여야 한다.

 

목적을 설명하거나 대상의 의도를 설명하는 이름을 사용한다.

가로로 이름이 길어지는걸 걱정하느니 읽는 사람이 바로 알아보는게 훨씬 낫다.

다른 사람이 딱 봤을때 잘 모를 것 같은 약어 사용은 지양한다.(특히 줄임말, 이니셜) 

문자 사이사이에 알파벳을 지워서 약어를 만들지 말아야 한다.

Wikipedia에 있는 약어정도는 괜찮을 수 있다.

이름이 나타내는 뜻은 그게 쓰이는 범위에 비례해야 한다.

예를 들어 n같은것은 5줄 내외의 함수에서는 괜찮을 수 있지만, 클래스 입장에서 보면 너무 모호하다.

 

<<< GOOD >>>
class MyClass {
 public:
  int CountFooErrors(const std::vector<Foo>& foos) {
    int n = 0;  // 짧은 범위 안에서 쓰이므로 의미가 명확함
    for (const auto& foo : foos) {
      ...
      ++n;
    }
    return n;
  }
  void DoSomethingImportant() {
    std::string fqdn = ...;  // Fully Qualified Domain Name의 유명한 약자
  }
 private:
  const int kMaxAllowedConnections = ...;  // 문맥 내에서 명확한 의미
};
<<< BAD >>>
class MyClass {
 public:
  int CountFooErrors(const std::vector<Foo>& foos) {
    int total_number_of_foo_errors = 0;  // 짧은 범위에서 쓰이지만 말이 너무 많음
    for (int foo_index = 0; foo_index < foos.size(); ++foo_index) {  // 관용적으로 `i`를 쓰는게 나음
      ...
      ++total_number_of_foo_errors;
    }
    return total_number_of_foo_errors;
  }
  void DoSomethingImportant() {
    int cstmr_id = ...;  // customer를 사이사이 빼서 줄였음
  }
 private:
  const int kNum = ...;  // 넓은 범위 내에서 의미가 불명확함
};

반복문 안에서 i와 템플릿 T같이 잘 알려진 약어는 상관없다.

 

아래 네이밍 규칙에서 "단어"는 띄어쓰기 없이 영어로 작성하는 모든것을 의미한다.

여기에는 두문자어(HTTP처럼 앞글자 따서 만든 것)같은 축약어도 포함된다.

각 단어의 첫글자가 대문자로 쓰인 이름(예를 들어 MyName같은 것, camel case, pascal case라고도 함)도 약어를 대문자로 표시한다. e.g., StartRpc() 대신 StartRPC()로 씀

(추가: 대소문자를 섞어서 쓴다고 하면 대부분 이 표현방식임)

 

템플릿 파라미터는 해당 카테고리의 이름 스타일을 따라야 한다.

자료형 템플릿 파라미터(type template parameters)는 타입 이름의 규칙을 따르고, 자료형이 아닌 템플릿 파라미터(non-type template parameters)는 변수 이름의 규칙을 따라야 한다.


파일(File) 이름

파일 이름은 모두 소문자여야 하고, 밑줄(_)이나 대시(-)를 쓸 수 있다.

밑줄이나 대시는 프로젝트 규칙에 따르고, 만약 따로 없으면 밑줄이 낫다.

예시)

  • my_useful_class.cc
  • my-useful-class.cc
  • myusefulclass.cc
  • myusefulclass_test.cc // _unittest 와 _regtest 는 더이상 안쓰임

C++의 파일은 .cc로 끝나야 하고, 헤더는 .h로 끝낸다.

특정 시점에 원문대로 포함되어야 하는 파일은 .inc로 끝낸다.(자체 포함 헤더 참조)

 

db.h같이 /usr/include에 이미 존재하는 파일 이름은 쓰지않는다.

 

일반적으로 파일 이름을 매우 구체적으로 적는게 좋다.

예를 들어 logs.h보다 http_server_logs.h처럼 이름을 짓는게 좋다.

가장 일반적인건 이름이 같은 쌍으로 만드는 것이다.

예를 들면 foo_bar.h와 foo_bar.cc에 FooBar클래스가 정의되도록 이름을 짓는게 좋다.


자료형(Type) 이름

자료형 이름은 대문자로 시작하고, 각 단어마다 밑줄 없이 다시 대문자로 시작한다.(MyExcitingClass, MyExcitingEnum처럼)

 

모든 자료형의 이름(클래스, 구조체, 자료형 별칭(type aliases), 열거형, 자료형 템플릿 파라미터(type template parameters)은 같은 네이밍 규칙을 사용한다.

자료형의 이름은 대문자로 시작하고, 각 단어의 시작마다 밑줄을 안쓰고 대문자로 쓴다. 

// 클래스, 구조체
class UrlTable { ...
class UrlTableTester { ...
struct UrlTableProperties { ...

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

// 별칭 사용
using PropertiesMap = hash_map<UrlTableProperties *, std::string>;

// 열거형
enum class UrlTableError { ...

변수(Variable) 이름

변수 이름(함수의 매개변수 포함)과 멤버변수의 이름은 전부 소문자이며, 단어 사이에 밑줄을 사용한다.

클래스의 멤버변수(구조체 제외)는 이름 맨 마지막에 밑줄을 추가 해 준다.

예) 지역변수: a_local_variable, 구조체 멤버: a_struct_data_member, 클래스 멤버: a_class_data_member_

일반적인 변수이름

<<< GOOD >>>
std::string table_name;	// 밑줄과 소문자로 잘 했음
<<< BAD >>>
std::string tableName;	// 대소문자 혼합했음

클래스의 멤버변수

정적이든 비정적이든(static, non-static) 클래스의 멤버변수는 일반적인 변수이름처럼 짓고 뒤에 밑줄만 추가한다.

class TableInfo {
  ...
 private:
  std::string table_name_;  // OK - 끝에 밑줄
  static Pool<TableInfo>* pool_;  // OK.
};

구조체의 멤버변수

정적이든 비정적이든(static, non-static) 구조체의 멤버변수는 일반적인 변수이름처럼 짓는다. 클래스 멤버변수같이 밑줄 치지 않는다.

struct UrlTableProperties {
  std::string name;
  int num_entries;  // OK - 끝에 밑줄 안함
  static Pool<UrlTableProperties>* pool;  // OK.
};

상수(Constant) 이름

constexpr이나 const로 선언한 변수와 프로그램이 도는 동안 값이 고정된 변수는 이름 맨 앞에 k를 붙이고 대소문자를 섞어서 이름을 짓는다.

가끔 대문자로 구분을 못하는 경우가 있는데, 그럴땐 밑줄을 쓰면 된다.

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

함수(Function) 이름

일반 함수들은 대소문자를 섞어서 이름을 짓는다. 접근자(accessors)와 설정자(mutators)들은 변수이름처럼 짓는다.

(추가: 접근자는 멤버변수 값을 반환하는 멤버함수고, 설정자는 멤버변수 값을 변경하는 멤버함수다. 예를 들면 get~~(), set~~() 같은 것들)

 

일반적으로 함수는 대문자로 시작하고, 단어 하나하나마다 대문자로 시작한다.

AddTableEntry()
DeleteUrl()
OpenFileOrDie()

 

(API의 일부로 노출되거나 함수처럼 보이게 만든 클래스와 네임스페이스 안의 상수에도 같은 네이밍 규칙이 적용된다. 함수가 아니라 객체라는 사실이 구현 디테일에는 중요하지 않기 때문이다.)

(The same naming rule applies to class- and namespace-scope constants that are exposed as part of an API and that are intended to look like functions, because the fact that they're objects rather than functions is an unimportant implementation detail.)

 

접근자(accessors)와 설정자(mutators)(get과 set함수)는 변수처럼 이름을 지정할 수 있다.

가끔 실제 멤버변수와 같은 이름일 수 있고, 필수로 변수처럼 지정해야 하는것은 아니다.

예를 들어 int count()와 void set_count(int count)


네임스페이스(Namespace) 이름

네임스페이스 이름은 모두 소문자고, 각 단어는 밑줄로 구분한다.

최상위 네임스페이스 이름은 프로젝트 이름을 기반으로 만든다.

잘 알려진 최상위 네임스페이스 이름과 중첩 네임스페이스(nested namespaces)간의 충돌을 피한다.

(Avoid collisions between nested namespaces and well-known top-level namespaces.)

(추가: 아래와 같은 형태를 nested namespace라고 함)
namespace A{
  namespace B{
    namespace C{
      void foo(){
        std::cout<<"Nested namespace example"<<std::endl;
      }
    }
  }
}

 

최상위 네임스페이스 이름은 주로 해당 네임스페이스에 작업하는 프로젝트나 팀의 이름으로 한다.

해당 네임스페이스의 코드는 네임스페이스와 이름과 같은 디렉토리(또는 그 하위 디렉토리)에 있어야 한다.

 

축약어를 사용하지 않는 규칙은 변수이름 짓는것처럼 네임스페이스에도 적용된다.(즉, 축약어 지양하라는 뜻)

네임스페이스 안의 코드에서 네임스페이스 이름을 쓰는 경우는 거의 없으므로 약어를 쓸 필요가 없다.

 

최상위 네임스페이스와 같은 이름의 중첩 네임스페이스(nested namespaces)를 만드는 것을 피해야 한다.

네임스페이스끼리 충돌은 아주 치명적이다.

특히, 어떤 경우에도 중첩된 std 네임스페이스를 만들면 안된다.

중복될 가능성이 높은 이름(websearch::utili)보다 고유한 프로젝트 식별자(websearch::index, websearch::index_util)를 쓰는게 낫다.

또한 네임스페이스가 너무 깊게 중첩(deep nesting)되지 않게 한다.(TotW #130).

 

internal 네임스페이스의 경우 다른 코드에 추가된 internal 네임스페이스와의 충돌에 주의해야 한다.

(팀 내의 internal helpers는 서로 관련되는 경향이 있어 충돌이 일어날 수 있다.)

이러한 상황에서는 파일 이름을 사용해 고유한 internal name을 만드는 것이 좋다.

(frobber.h에서는 websearch::index::frobber_internal로 사용)


열거형(Enumerator) 이름

 

728x90

'개발 > C, C++' 카테고리의 다른 글

[C++] STL 2편 - 벡터 컨테이너(vector)  (0) 2022.07.07
[C++] STL 1편 - STL이란?  (0) 2022.07.07
[C++] XOR 연산 이용 swap  (0) 2022.06.12
[C++] 참조자(Reference), 포인터와 차이점, 사용법  (0) 2022.06.10
[C++] namespace란?  (0) 2022.06.10
COMMENT