[UE] 문자타입, 문자열 FString, FText, FString
언리얼 C++의 기본 타입과 문자열 다루는 방법 소개
- 언리얼 환경에서 알아두어야 할 기본 타입과 고려할 점
- 캐릭터 인코딩 시스템에 대한 이해
- 언리얼 C++이 제공하는 다양한 문자열 처리 방법과 내부 구성의 이해
인프런 이득우님의 '언리얼 프로그래밍 Part1 - 언리얼 C++의 이해' 강의를 참고하였습니다.
😎 [이득우의 언리얼 프로그래밍 Part1 - 언리얼 C++의 이해] 강의 들으러 가기!
목차
언리얼 C++ 기본 타입
언리얼은 C++의 기본 타입
1970년대에 개발된 C++언어는 기기들마다 C++ 언어를 구현하는 방법이 달라서 C++ 주요 함수가 특정 플랫폼에서 다르게 작동하는 플랫폼 파편화 (Platform Fragmentation) 문제가 발생했다.
게임 제작에서는
- 데이터 정보가 명확해야 한다.
- 단일 컴퓨터에서 최대 퍼포먼스를 뽑아내야 한다.
- 네트웍 상에서 데이터 통신이 효율적이고 안정적이어야 한다.
그렇기 때문에 언리얼 엔진은 데이터 타입의 모호함을 없애기 위해 언리얼 자체 기본 타입을 만들었다.
데이터 타입의 애매 모호함은 게임 개발 시 문제를 일으킬 수 있음
bool 타입의 선언
- 데이터 전송을 고려한 참, 거짓 데이터의 지정
- `.h` 헤더에서는 가급적 `bool` 대신 `uint8` 타입을 사용하되 Bit Field 오퍼레이터를 사용해서 데이터 크기를 제한해 최소화시킬 수 있다.
- 일반 `uint8` 과의 구분을 위해, `b` 접두사를 사용하도록 코딩 표준에 명시되어 있다.
- .cpp 로직에서는 자유롭게 bool을 사용해도 무방하다.
UPROPERTY()
uint8 bNetTemporary:1;
uint8 bNetStartup:1;
UPROPERTY(Category=Replication, EditDefaultOnly, BlueprintReadOnly)
uint8 bOnlyRelevantToOwner:1;
UPROPERTY(Category=Replication, EditDefaultOnly, BlueprintReadWrite)
uint8 bAlwaysRelevant:1;
언리얼의 문자열
언리얼이 문자열을 따로 지정하는 이유는?
- 1990년대 후반에 Unicode라는 새로운 표준을 통해 모든 국가의 문자를 표현할 수 있게 되었다.
- 하지만, 컴퓨터는 그 전에 보급되었다.
- 문자열 처리의 종류
- Single byte
- Multibyte
- Unicode
- Unicode보다 먼저 등장한 Multibyte 표현방법이 아직도 사용이 되고 있다.
- C++ STL은 ASCII, UTF-8, UTF-16만 지원함
이 상황을 해결하기 위해서 언리얼에서는 TCHAR을 이용한다.
언리얼은 내부적으로 UTF-16을 사용한다.
복잡한 문자열 처리를 하나로
- 유니코드(Unicode)를 사용해 문자열 처리를 통일
- 이 중에서 2byte로 사이즈가 균일한 UTF-16을 사용
- 유니코드를 위한 언리얼 표준 캐릭터 타입: TCHAR
- 문자열은 언제나 TEXT 매크로를 사용해 지정
- TEXT 매크로로 감싼 문자열은 TCHAR 배열로 지정됨
- 문자열을 다루는 클래스로 FString을 제공함
- FString은 TCHAR 배열을 포함하는 헬퍼 클래스
#include "MyGameInstance.h"
void UMyGameInstance::Init()
{
Super::Init();
TCHAR LogCharArray[] = TEXT("Hello Unreal!");
UE_LOG(LogTemp, Log, TEXT("%s"), LogCharArray);
FString LogCharString = LogCharArray;
UE_LOG(LogTemp, Log, TEXT("%s"), *LogCharString); // *연산자를 붙여줘야 FString이 감싸고 있는 실제 문자열 데이터를 가져올 수 있다.
}
FString의 구조와 활용
- 다른 타입에서 FString으로의 변환
- FString::Printf
- FString::SanitizeFloat
- FString::FromInt
- FCString 래퍼 클래스로 C 런타임 수준에서 문자열을 처리하는 함수를 사용할 수 있다.
- ex. 문자열을 찾는 strstr, 문자열 복사 strcpy, strcmp, 등등
- FString에서 다른 타입으로의 변환 (안전하지 않으므로 주의)
- FCString::Atoi
- FCString::Atof
※ 참고사항: 직렬화(Serialization) 후 변환되는
- 직렬화(Serialization)을 거친 모든 오브젝트와 변수들은 '0, 1로 이루워진 String(= 즉, bit array)'으로 변경된다.
- 직렬화된 정보들은 나열된 정보로 저장된다.
- CoreNet.h 내의 UPackageMap을 사용해서 직렬화된 정보를 사용
TCHAR와 FString 이용한 문자열 처리
#include "MyGameInstance.h"
void UMyGameInstance::Init()
{
Super::Init();
const TCHAR* LogCharPtr = *LogCharString;
// std::string::data() 같은 느낌인듯 하다.
TCHAR* LogCharDataPtr = LogCharString.GetCharArray().GetData();
// 대소문자 구분 없이 "Unreal"이란 문자열을 찾음. 리턴 값은 bool형
if (LogCharString.Contains(TEXT("Unreal"), ESearchCase::IgnoreCase))
{
// 대소문자 구분 없이 "Unreal"이란 문자열이 시작하는 위치를 찾음.
int32 Index = LogCharString.Find(TEXT("Unreal"), ESearchCase::IgnoreCase);
// Index 위치부터 끝까지의 부분문자열을 리턴. substr
FString EndString = LogCharString.Mid(Index);
UE_LOG(LogTemp, Log, TEXT("Find Test: %s"), *EndString);
}
}
문자열 코드 출력하기 코드
#include "MyGameInstance.h"
void UMyGameInstance::Init()
{
Super::Init();
FString LeftString, RightString;
if (LogCharString.Split(" ", &LeftString, &RightString)) // " "(공백)을 기준으로 문자열을 두개의 부분 문자열로 분리
{
// 한글을 사용하기 위해선 UTF-8(Unicode 65001)로 인코딩해야 함.
UE_LOG(LogTemp, Log, TEXT("Split Test: %s 와 %s"), *LeftString, *RightString);
}
int32 IntValue = 32;
float FloatValue = 3.141592;
// FString::SanitizeFloat, FString::FromInt를 이용해 정수형, 실수형 변수를 문자열로 전환
// FString::Printf의 경우, 출력하는 함수가 아닌 FString을 반환하는 함수다
FString FloatIntString = FString::Printf(TEXT("Int: %d, Float: %f"), IntValue, FloatValue);
FString FloatString = FString::SanitizeFloat(FloatValue);
FString IntString = FString::FromInt(IntValue);
UE_LOG(LogTemp, Log, TEXT("%s"), *FloatIntString);
UE_LOG(LogTemp, Log, TEXT("Int: %s, Float: %s"), *IntString, *FloatString);
}
FName의 활용
언리얼이 제공하는 다양한 문자열 처리
FName | 애셋 관리를 위해 사용되는 문자열 체계
|
FText | 다국어 지원을 위한 문자열 관리 체계
|
FName 구조와 활용
- 언리얼은 FName과 관련된 글로벌 Pool 자료구조를 가지고 있음
- FName과 글로벌 Pool
- 문자열이 들어오면 해시 값을 추출해 Key를 생성해 FName에서 보관
- FName 값에 저장된 값을 사용해 전역 Pool에서 원하는 자료를 검색해 반환
- 문자 정보는 대소문자를 구분하지 않고 저장함. (Ignore Case)
- FName의 형성
- 생성자에 문자열 정보를 넣으면 풀을 조사해 적당한 키로 변환하는 작업이 수반됨
- Find or Add
문자가 들어왔을때 문자열 정보가 저장되는 것이 아니라 Key값이 저장됨. 문자열은 다른곳에 따로 저장됨.
FName 예시 코드
#include "MyGameInstance.h"
void UMyGameInstance::Init()
{
Super::Init();
// 문자열이 해시테이블을 통해 key값으로 변환
FName key1(TEXT("PELVIS"));
FName key2(TEXT("pelvis"));
UE_LOG(LogTemp, Log, TEXT("FName 비교 결과: %s"), key1 == key2 ? TEXT("같음") : TEXT("다름"));
// 아래와 같이 매번 실행하게 하면, 오버헤드가 발생한다.
// Tick과 같이 자주 실행되는 곳에 FName을 사용하는 경우, 오버헤드가 발생할 수 있다.
for (int i = 0; i < 10000; i++)
{
FName SearchInNamePool = FName(TEXT("pelvis")); // 생성자에 문자열을 넣음. pelvis
}
// StationOnlyOnce로 처음 초기화할 때 저장한 뒤에는 그 후에는 찾을 일이 없다.
for (int i = 0; i < 10000; i++)
{
FName SearchInNamePool = FName(TEXT("pelvis")); // 생성자에 문자열을 넣음. pelvis
const static FName StaticOnlyOnce(TEXT("pelvis"));
}
}
'⭐ Unreal Engine > UE 개념정리 - 언리얼의 이해' 카테고리의 다른 글
[UE] 언리얼 리플렉션 Unreal Reflection II (0) | 2024.03.21 |
---|---|
[UE] 언리얼 리플렉션 Unreal Reflection I (0) | 2024.03.18 |
[UE] 언리얼 오브젝트 시스템 (0) | 2024.03.18 |
[UE] 언리얼 C++ 코딩 표준 (0) | 2024.03.06 |
[UE] Hello Unreal (0) | 2024.03.06 |
댓글
이 글 공유하기
다른 글
-
[UE] 언리얼 리플렉션 Unreal Reflection I
[UE] 언리얼 리플렉션 Unreal Reflection I
2024.03.18 -
[UE] 언리얼 오브젝트 시스템
[UE] 언리얼 오브젝트 시스템
2024.03.18 -
[UE] 언리얼 C++ 코딩 표준
[UE] 언리얼 C++ 코딩 표준
2024.03.06 -
[UE] Hello Unreal
[UE] Hello Unreal
2024.03.06