기본타입과 문자열

myeongrangcoding·2023년 11월 28일
  • 기본 타입과 고려할 점
  • 캐릭터 인코딩 시스템
  • 문자열 처리 방법과 내부 구성

언리얼 C++ 기본 타입

  • 플랫폼 파편화: 예: C++의 주요한 함수가 특정 플랫폼에서 다르게 동작, int형의 크기(최소 32bit) 확신할 수 없음, 네트워크 상에서 데이터 통신이 효율적이고 안정적이기 위해서는 데이터 정보가 명확해야 한다.

  • (데이터 전송을 고려한)bool 타입 선언

    1. 크기가 명확하지 않음.(bool의 size에 대해 명확히 규정하고 있지 않다.)
    2. 헤더에는 bool 대신 uint8 타입 사용, Bit Field 오퍼레이터 사용.
      uint8 bNetTemporary:1;
    3. 일단 uint8과의 구분 위해 b접두사 사용.
    4. 데이터를 저장하는 데 있어서 고려사항이기 때문에 Cpp에서는 bool 사용.

    Bit Field

    struct non_bit_field {
      unsigned b1;
      unsigned b2;
      unsigned b3;
    };
    
    struct bit_field {
      unsigned b1: 1;
      unsigned b2: 2;
      unsigned b3: 4;
    };
    
    int main() {
      cout << sizeof(non_bit_field) << endl;  	// 12.
      cout << sizeof(bit_field) << endl;  		// 4.
    }

언리얼 문자열

  • TCHAR 사용.

    ASCII, ANSI: 서구권 국가들에 대해서만 한정적으로 만들어졌던 타입.
    UTF-8, UTF-16: 동아시아 국가들의 문자열셋을 감안한 국제 표준 유니코드.

  • UTF-8: ASCII 상위집합. 영문권 캐릭터에는 한 바이트 사용, 동아시아 캐릭터에는 두 바이트 사용.
  • UTF-16: 무조건 2바이트로 저장하는 방식.
  • 언리얼은 내부적으로 모두 UTF-16.
  • 소스 코드에 한글을 사용하겠다 하면 UTF-8 방식으로 저장.

FString

  • ToString이라는 함수를 제공해서 FString으로 변환.
  • 디버깅 할 때 각 데이터들을 편리하게 살펴볼 수 있다.

FString 활용

  • FString::Printf
  • FString::SanitizeFloat
  • FString::Fromlnt

FCString

  • C 스트링 관련 함수들을 포함하고 있는 래퍼 클래스.
  • FCString::Atoi
  • FCString::Atof

예제

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

	static const TCHAR LogCharArray[] = TEXT("Hello Unreal");
	UE_LOG(LogTemp, Log, LogCharArray);

	FString LogCharString = LogCharArray;

	// TEXT("%s"): 배열만 들어가기 때문에 FString을 쓸 수가 없다.
	// *LogCharString: *연산자를 붙여줘야지만 FString이 감싸고 있는 실제 문자열 데이터를 가져올 수가 있게 된다.
	UE_LOG(LogTemp, Log, TEXT("%s"), *LogCharString);

	// FString을 const TCHAR*로.
	const TCHAR* LongCharPtr = *LogCharString;
	// FString을 TCHAR*로.
	TCHAR* LogCharDataPtr = LogCharString.GetCharArray().GetData();
	// FString을 TCHAR 배열로.
	TCHAR LogCharArrayWithSize[100];
	FCString::Strcpy(LogCharArrayWithSize, LogCharString.Len(), *LogCharString);

	// Contains: TEXT("")가 있는지 검사.
	// ESearchCase::IgnoreCase: 대소문자 구분 없음.
	if (LogCharString.Contains(TEXT("unreal"), ESearchCase::IgnoreCase))
	{
		// Find: TEXT("")를 찾아 인덱스 반환.
		int32 Index = LogCharString.Find(TEXT("unreal"), ESearchCase::IgnoreCase);
		// Index부터 끝까지 자름.
		FString EndString = LogCharString.Mid(Index);
		UE_LOG(LogTemp, Log, TEXT("Find Test: %s"), *EndString);
	}

	FString Left, Right;
	// Split: TEXT("") 기준 문자열 분리.
	if (LogCharString.Split(TEXT(" "), &Left, &Right))
	{
		// 와 가 이상하게 출력.
		// 윈도우에서 한글을 썼기 때문에 CP949 형태의 멀티 바이트 스트링으로 저장됨.
		// UTF-16을 쓰는 언리얼과 호환이 안 됨.
		// UTF-8 with signature로 저장하면 잘 출력됨.
		UE_LOG(LogTemp, Log, TEXT("Split Test: %s 와 %s"), *Left, *Right);
	}

	int32 IntValue = 32;
	float FloatValue = 3.141592;

	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);

	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);
}

FName 클래스

  • 에셋 관리를 위해 사용되는 문자열 체계.
  • 찾기 위한 클래스.
  • 실제적인 자료는 key 값만 들어가 있기 때문에 용량은 굉장히 작다.
  • FNamePool에 데이터가 있는지 찾거나, 없으면 추가하거나.
  • 문자열을 사용하지만 내부적으로는 해시값을 사용해서 바로바로 찾을 수 있게 함.
  • 대소문자 구분 없고, 한 번 선언되면 key로 만들어지는 것이기 때문에 바꿀 수 없음.

FText 클래스

  • 게임 빌드 시 자동으로 다양한 국가별 언어로 변환.
  • UI 다국어 지원을 할 때 필요한 문자열 관리 체계.

즉, FString을 사용해서 문자열 관리를 하는데 FName, FText로 변환해가지고 다양한 용도로 사용할 수 있다.


예제

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

	// 대소문자 구분하지 않음.
	// PELVIS는 해시값으로 변환돼서 FName에는 문자열 정보가 들어가는 것이 아니고 키값만 들어감.
	FName key1(TEXT("PELVIS"));
	FName key2(TEXT("pelvis"));
	UE_LOG(LogTemp, Log, TEXT("FName 비교 결과: %s"), key1 == key2 ? TEXT("같음") : TEXT("다름"));

	// 문자열을 key로 변환한 다음 그 key가 전역 풀에 있는지 조사하는 작업을 거친다.
	FName SearchInNamePool = FName(TEXT("pelvis"));
	// 틱 같은 함수에 넣어 가지고 실행하게 되면 오버헤드가 발생할 수 있기 때문에 local static으로 사용하는 것이 더 효과적이다.
	const static FName StaticOnlyOnce(TEXT("pelvis"));
}

profile
명랑코딩!

0개의 댓글