게임 개발/언리얼 C++

언리얼C++ - 언리얼 코딩 규칙

싹난 감자 2024. 11. 9. 16:20

코딩 표준(Coding Standard)

  • 코드를 작성하는데 지켜야하는 프로그래밍 이름 규칙, 작성 방법 등을 지정한 가이드라인
  • 코딩 스타일(Coding Style), 코딩 컨벤션(Coding Convention)이라고도 함

회사나 팀 내의 코딩 규칙을 잘 따라야함,

모든 코드는 한 사람이 만든 것처럼 보여져야함.

https://google.github.io/styleguide/cppguide.html | 구글 코딩 스타일

 

Google C++ Style Guide

Google C++ Style Guide Background C++ is one of the main development languages used by many of Google's open-source projects. As every C++ programmer knows, the language has many powerful features, but this power brings with it complexity, which in turn ca

google.github.io

 

언리얼 엔진은 자체적으로 정한 코딩 표준이 있다.

엔진의 소스 코드가 해당 표준을 따라 작성되어 있기 때문에 언리얼 C++ 표준을 따라야함.

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/epic-cplusplus-coding-standard-for-unreal-engine?application_version=5.1 | 언리얼 C++ 코딩 표준

 

 

언리얼 C++ 코딩 표준

클래스 체계 |

언리얼 클래스를 생성하여 코드 템플릿이 주어지면 public을 먼저 선언해라.

해당 코드를 읽는 사람들은 보통 public으로 선언되어 있는 것들을 사용할테니

public 구현 후 private 구현을 하는 구조로 작성해야한다.

저작권 고지 |

배포되어 있는 소스 파일의 저작권 고지를 임의로 수정하면 오류가 발생한다.

명명규칙 |

모든 코드 및 코멘트는 미국 영어의 철자법 및 문법을 사용한다.

  • 각 단어의 첫 번째 글자(타입 이름 또는 변수 이름)는 대문자여야 한다. (파스칼 케이스)
  • 타입 이름에는 추가적으로 대문자로 이루어진 접두사를 포함하여 변수 이름과 구분한다.
    • FSkin 은 타입 이름이고, Skin 은 FSkin 타입의 인스턴스.
  • 템플릿 클래스에는 접두사 T를 포함한다.
    • class TAttribute
  • UObject에서 상속하는 클래스에는 접두사 U를 포함한다.
    언리얼에서 새로운 클래스를 만들 때 모든 클래스는 Object라는 클래스를 상속받아 작성하도록 되어있기 때문에 클래스 명이 U로 시작해야함.
    • class UActorComponent
  • Actor라는 클래스를 상속받은 클래스는 접두사 A로 시작해야한다. 
    • class AActor
  • Wiget라는 클래스를 상속받으면 접두사 S로 시작한다.
    • class SCompoundWidget
  • 추상적 인터페이스인 클래스는 접두사 I로 시작한다.
    • class IAnalyticsProvider
  • 열거형(enum)접두사 E로 시작한다.
    • enum class EColorBits
  • 부울(bool) 변수접두사 b로 시작한다.
    • bHasFadedIn
    • 예외적으로 소문자.
  • 그 외에 대부분은 접두사 F로 시작한다.
    • 일반적인 C++ 클래스구조체언리얼 오브젝트를 상속받지 않는 클래스들은 F를 사용.

이 외에 일반적인 규칙들

함수 내에서 입력으로만 사용할 것인지 함수 밖에서도 쓰이는지 등을 알리기 위한 In/Out을 추가하는 것이 좋다.

bool의 경우 정확히 어떤 의미인지 알 수 있게 명명하는 것이 중요

변수 타입

  • int형 변수를 사용할 때 int8, int16, int32와 같이 몇 바이트를 사용할 것인지 명시해줘야한다.
    • 보통 4바이트를 많이 사용하는데 uint8, int32등도 주요하게 사용됨
    • C++의 int는 최대 크기를 보장하지 않지만 최소 크기는 32비트로 보장된다. 때문에 크기를 명시해주어야함.
  • char형 변수를 사용할 때 TCHAR이라는 타입을 사용한다.

표준 라이브러리

언리얼 자체 라이브러리가 아닌 C++ 표준 라이브러리를 사용할 수 있지만 표준 라이브러리는 범용적이고 문제점이 있을 수 있다. 최적화된 언리얼 자체 라이브러리를 사용하지 않을 이유는 없다.

Const 정확도

일반적인 C++ 문법

수정되지 않는 변수는 const로 선언하여 분명하게 하는 것이 좋다. 컴파일 타임에 사전에 체크해주기 때문에 코드의 정확성이 높아진다.

대표적으로 loop를 돌 때, 각 요소를 돌 때 엘리먼트에 대해서는 지정해주는 것이 좋다.

  • 포인터에 대한 const
    • T* const Ptr = …; : 좋은 예
      • 포인터가 가리키는 것이 아니라 포인터의 자체를 const로 만들 수 있다.포인터가 가리키는 값(T)은 const가 아니기 때문에 변경할 수 있다.
      • 연산자에 대해서 증감 연산 등을 할 수 없다.
    • T& const Ref = …; : 나쁜 예
      • 레퍼런스는 이미 재할당이 불가능하며, 레퍼런스 자체가 const라는 의미를 가지고 있기 때문에 const로 지정하는 것이 문법적으로 맞지 않다.
    • const TArray<FString> GetSomeArray(); : 나쁜 예 - const 배열 반환
      • 배열을 반환하는 경우 레퍼런스로 지정이 되지 않고 복사가 일어나기 때문에 const가 적합하지 않다.
    • const TArray<FString>& GetSomeArray(); : 좋은 예 - const 배열로의 레퍼런스 반환
      • TArray의 주소를 가리켜 배열의 값을 바로 사용하기 때문에 const를 사용하면 배열의 값을 변경하지 않는다는 뜻
    • const TArray<FString>* GetSomeArray(); : 좋은 예 - const 배열로의 포인터 반환
      • 포인터에 const가 되어있지 않기 때문에 포인터는 증감 연산이 가능, 이 포인터가 일으키는 데이터는 바뀌면 안된다.
    • const TArray<FString>* const GetSomeArray(); : 나쁜 예 - const 배열로의 const 포인터 반환
      • 포인터도 고칠 수 없고 포인터에 있는 값도 바뀌어서는 안된다. 이런 경우는 거의 없다.

자동 문서화

에픽에서는 JavaDoc 기반 시스템을 사용하여 코드에서 코멘트를 자동으로 추출한 뒤 문서를 만듦.

주석을 포맷에 맞추어 작성하면 쉽게 문서화 할 수 있음

nullptr

C 스타일 NULL을 사용하면 안됨

NULL 대신 nullptr이라는 타입을 사용

‘auto’키워드

auto를 사용하지 않는 것을 권장. 가능한 사용 자제

  • 람다 타입을 사용해야하는 경우
  • 타입이 복잡하여 가독성에 악영향을 끼치는 경우 사용

Enum

// enum class가 지원되지 않을 때의 열거형
UENUM()
namespace EThing
{
	enum Type
	{
		Thing1,
		Thing2
	};
}

// 기존 프로퍼티
UPROPERTY()
TEnumAsByte<EThing::Type> MyProperty;

//enum class를 사용하는 열거형
UENUM()
enum class EThing : uint8
{
	Thing1,
	Thing2
}

// 새 프로퍼티
UPROPERTY()
EThing MyProperty;

이제는 enum class를 통해 열거형이 안정적으로 강화되었기 때문에 enum class를 사용하면 되나 예전 코드 중에는 과거의 방식으로 쓰여져있는 것들도 있을 수 있음

이동 시멘틱

언리얼 C++에서는 std를 사용하지 않기 때문에 std::move 대신 언리얼에서 구현한

MoveTemp 를 사용하면 된다. 자료구조를 사용할 때 메모리에 복사 없이 바로 옮길 수 있음

Find In Files

소스 코드의 내용을 검색하기 용이하도록 타입 명명 규칙등을 지킨다.

ex) FShaderType* Ptr : O

FShaderType *Prt : X

헤더파일과 #include

헤더 파일 및 #include 구문은 의존성을 최소화시켜 주의깊게 다뤄야 함.

헤더 파일 포맷

소스 파일(.cpp)의 구현은 다른 C++ 클래스와 같지만 헤더(.h)파일의 정의는 기본 구조를 준수해야함

#pragma once

#include 'Object.h'
#include 'MyObject.generated.h'

/**
*
*/
UCLASS()
class MYPROJECT_API UMyObject : public UObject
{
	GENERATED_BODY()
};

이득우의 언리얼 프로그래밍 Part1 | 인프런

https://www.inflearn.com/course/%EC%9D%B4%EB%93%9D%EC%9A%B0-%EC%96%B8%EB%A6%AC%EC%96%BC-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-part-1/dashboard

 

이득우의 언리얼 프로그래밍 Part1 - 언리얼 C++의 이해 강의 | 이득우 - 인프런

이득우 | 대기업 현업자들이 수강하는 언리얼 C++ 프로그래밍 전문 과정입니다. 언리얼 엔진 프로그래머라면 게임 개발전에 반드시 알아야 하는 언리얼 C++ 기초에 대해 알려드립니다., [사진] 언

www.inflearn.com