그냥 게임개발자

네번째 - 여러가지 문자열 사용 방법(TCHAR, FString) 본문

Unreal스터디/Unreal압축판

네번째 - 여러가지 문자열 사용 방법(TCHAR, FString)

sudoju 2024. 3. 12. 19:07

저번에 Hello, World를 UE_LOG라는 매크로를 통해 화면에 출력시켰죠?

 

이번에는 우리는 TCHARFString을 배울것입니다.

 

TCHAR

TCHAR가 뭐냐?

string같은 거다.

 

진짜 간단하게 이야기하자면 이게 끝이다.

왜 언리얼은 그러면 string을 사용하면 되지 왜 TCHAR를 만들어서 사용하는 거지?

라고 필자는 생각했었다.

 

일단 역사를 거슬러서 살펴보면 1990년대 후반에 이르러서야 아시아 문자열이 표준화가 되었다

뭐 한국어, 중국어, 일본어 등등 이런거 말이다.

하지만 컴퓨터는 아시아권에서 표준화가 되기도 전에 이미 사용이 되고 있었다.

 

영어는 1byte로 충분히 표현이 가능했지만, 아시아권 문자는 1byte로 표현이 불가능했었다.

그 때 당시에는 나름 각 국가별로 고유한 문자를 표현하기 위한 방법들을 구현해서 컴퓨터에 적용시키고 있었다.

우리나라에서는 EUC-KR이라는 체계로 시작되어 Windows95에서 이것을 발전시킨 CP949라는 체계로 만들어져서 한글을 처리하기 시작했었다.

 

이러한 체계를 Multibyte문자열이라고 한다.

 

근데 90년대 후반에 들어서 완전히 유니코드가 정착이 되어 이후에 나온 운영체제들은 다 유니코드를 지원하게 되는데, 문제는 마이크로소프트가 개발한 이 Multibyte 문자열 체계가 지금 아직도 Windows운영체제에 널리널리 쓰이고 있다는 것이다.

 

즉 Singlebyte(ANSI, ASCII), Multibyte(EUC-KR, CP949), Unicode(UTF-8, UTF-16) 우리가 처리해야 될 문자열이 총 3개가 된 것이다.

 

이 3개의 문자열을 한꺼번에 처리하고 해결해주는 것은 언리얼에서 TCHAR다.

 

후 오늘도 역사 공부 열심히했다.

사실 나도 이 글을 읽으면서 엥? 신기하면서도 각 사람들이 정말 많은 것을 만들었구나 라고 생각이 든다.

 

아무튼 그래서 TCHAR와 FString을 사용하는데

FString은 뭐야?

저번 글에 설명했다.

C++표준라이브러리가 생기기전에 이미 언리얼에서는 멀티플랫폼을 대체하기 위해 자체적으로 라이브러리를 만들었다.

그래서 FString을 사용한다고 한다.

 

그렇대요.

 

자 그러면 TCHAR와 FString을 사용해 출력을 해보자.

 

MyGameInstance.cpp

void UMyGameInstance::Init()
{
	Super::Init();
    
	static const TCHAR LogCharArray[] = TEXT("Hello, World");
	UE_LOG(LogTemp, Log, LogCharArray);
}

 

저번과 조금 다르지 않은가?

void UMyGameInstance::Init()
{
	Super::Init();
    
	UE_LOG(LogTemp, Log, TEXT("%s"), TEXT("Hello, World"));
}

이런식으로 사용했었는데 말이다.

 

사실 TEXT는 기본적으로 TCHAR의 배열이다.

 

아 그리고 UE5.1버전에서는 UE_LOG가 TCHAR 배열을 근야 써도 오류가 나지 않았지만, UE5.2 이상 부터는 static const를 지정해줘야 한다.

 

FString

 

만약 문자열을 다양하게 조합하고 싶다면 TCHAR 배열이 아닌 FString을 사용

void UMyGameInstance::Init()
{
	Super::Init();

	static const TCHAR LogCharArray[] = TEXT("Hello, World");
	UE_LOG(LogTemp, Log, LogCharArray);
	
	FString LogCharString = LogCharArray;
	UE_LOG(LogTemp, Log, TEXT("%s"), *LogCharString);
}

 

이런식으로 FString을 사용하면 되는데, FString은 TCHAR의 헬퍼 클래스이다.

그래서 여러가지 기능을 제공해준다.

데이터를 자르거나, 붙이거나, 새로운 방식으로 불러 들이거나 다양한 연산이 가능하다.

 

여기서 UE_LOG 매크로는 3번째 파라미터에는 항상 배열만 들어가는데

TCHAR는 배열이니 그냥 들어가고, FString은 %s에 대응 될 때 TCHAR의 포인터 Array를 반환해줘야 한다.

그니까 FString에 TCHAR의 배열을에 넣었을 때 TArray라고 하는 언리얼 엔진이 제공하는 동적 배열 클래스 방식으로 문자열을 보관한다.

 

이 동적 배열(FString)에서 다시 실제 데이터(TCHAR)를 꺼낼 때는 내부 자료에 대한 포인터를 가져와서 넘겨줘야 한다.

그래서 포인터 연산자를 사용하게 되면 FString에 포함하고 있는 동적배열 즉 TArray에 포함하고 있는 데이터의 첫번째 인자 포인터를 반환 해준다.

 

말이 어렵죠?

쉽게 말하면 FString에 들어있는 문자열은 포인터를 사용해 배출해줘야 데이터가 나온다라는 겁니다.

 

아래의 그림을 보면 좀 쉬울 거에요

 

FString에 대입할 때는 동적배열로 바뀌고 실제 문자열 데이터를 꺼낼때는 *연산자를 사용해 꺼내야 한다는 것!

이해 가셨죠?

 

 

 

이제 아까 말했듯이 FString 여러가지 기능이 붙어있는 문자열 클래스라고 했다.

 

여러가지 포인터 활용

static const TCHAR LogCharArray[] = TEXT("Hello, World");
FString LogCharString = LogCharArray;

// 불변하지 않는 포인터 배열을 생성
// FString의 TCHAR의 포인터 주소를 가져옴
const TCHAR* LongCharPtr = *LogCharString;

// 포인터를 받아 직접 고치고 싶으면 FString 안에
// TArray의 첫번째 인자의 포인터를 가져오는 방법
TCHAR* LogCharDataPtr = LogCharString.GetCharArray().GetData();

 

 

복사

// 배열로 가져오고 싶으면 저수준 복사 사용
TCHAR LogCharArrayWithSize[100];			// 배열 크기 설정

// 복사된 문자열이 저장될 배열, FString의 크기 만큼 버퍼지정
FCString::Strcpy(LogCharArrayWithSize, LogCharString.Len(), *LogCharString);

FCString은 C런타임 수준에서 문자열을 처리하는 클래스이다.

그니까 C라이브러리에서 제공하는 기본적인 스트링 관련 함수를 가지고 있다.

뭐 문자열 찾거나, 자르거나, 복사 등의 기능을 가지고 있고 그런 기능들을 처리 담당하는 클래스가 FCString이다.

 

 

검색과 자르기

// unreal string이 존재하는지와 조건은 
// ESearchCase::IgnoreCase(대소문자 구분X)
// ESearchCase::CaseSensitive(대소문자 구분O)
if (LogCharString.Contains(TEXT("unreal"), ESearchCase::IgnoreCase))
{
	// 몇 번째 인덱스에 unreal이라는 문자가 있는지 찾을 수 있음
	int32 Index = LogCharString.Find(TEXT("unreal"), ESearchCase::IgnoreCase);
	FString EndString = LogCharString.Mid(Index); // EndString은 unreal의 인덱스를 받았기에
	UE_LOG(LogTemp, Log, TEXT("Find Test : %s"), *EndString);	// unreal에 인덱스부터 출력
}

FString Left, Right;
if (LogCharString.Split(TEXT(" "), &Left, &Right))
{
	UE_LOG(LogTemp, Log, TEXT("Split Test : %s 와 %s"), *Left, *Right)
}

어려워 보인다 어려워 보여.

천천히 읽으면 안어렵다.

Split이 자르기 라는 함수도 알고 Find가 찾는 함수라는 것도 알고 ㅇㅇ

천천히 읽어보기 바란다.

 

FString int32, float

// ASCII To Int를 활용해 int로 변환
int32 IntValueFromString = FCString::Atoi(*IntString);
float FloatValueFromString = FCString::Atof(*FloatString);
FString FloatIntString2 = FString::Printf(TEXT("Int:%d Float:%f"), IntValueFromString, FloatValueFromString);

UE_LOG(LogTemp, Log, TEXT("%s"), *FloatIntString2);

 

int32, float → FString

FString NewString = FString::FromInt(YourInt);
 
FString VeryCleanString = FString::SanitizeFloat(YourFloat);

 

다음에는 FName으로... 오늘은 좀 진지하게 써버렸네;;

'Unreal스터디 > Unreal압축판' 카테고리의 다른 글

세번째 - 언리얼 C++ 코딩 표준  (2) 2024.03.12
두번째 - Hello World  (2) 2024.03.12
첫번째 - 시작하기전 각오  (0) 2024.03.10