[UE5] FName, FText, FString

2026. 3. 28. 13:11·게임개발/Unreal Engine

언리얼에서 개발을 하다 보면 헷갈리는 문자열 타입 3가지가 있다.

FName, FText, FString

셋 다 문자열을 처리하는데 어디에, 어떤 식으로 사용되는 것일까?

 


1. FName

콘텐츠 브라우저에서 새 에셋 이름을 지을 때, 다이내믹 머티리얼 인스턴스의 파라미터를 변경할 때, 스켈레탈 메시에서 본에 접근할 때, 모두 FName을 사용합니다. FName 은 문자열 사용에 있어서 초경량 시스템을 제공하는데, 주어진 문자열이 재사용된다 해도 데이터 테이블에 한 번만 저장되는 것입니다. FName 은 대소문자를 구분하지 않습니다. 변경도 불가능하여, 조작할 수 없습니다. 이처럼 FName의 정적인 속성과 저장 시스템 덕에 찾기나 키로 FName에 접근하는 속도가 빠릅니다. FName 서브시스템의 또 다른 특징은 스트링에서 FName 변환이 해시 테이블을 사용해서 빠르다는 점입니다.

 

즉, 기존 C++의 문자열 방식보다 더 빠르고 가볍다는 장점이 있으며 언리얼 에디터에서 주로 사용되는 타입이다.

1-1. 변환

FName -> FString / FText로 가능하며, FString -> FName만 가능하다.

// From FName
// FName -> FString
TestHUDString = TestHUDName.ToString();

// FName -> FText
// 이 경우 FText의 현지화 데이터 손실이 존재한다.
TestHUDText = FText::FromName(TestHUDName);

// To FName
// FString -> FName
// FName은 대소문자 구분이 없으므로 주의해야한다.
TestHUDName = FName(*TestHUDString);

 

1-2. 비교

FName비교는 1) == 연산자와 2) FName::Compare을 사용해 비교할 수 있다.

 

1) == 연산자

실제 문자열 비교가 아닌, Index 안의 값을 비교하여 CPU 값을 크게 절약할 수 있다.

NameTypes.h에 작성된 연산자 오버로딩을 보면 아래처럼 나와있다.

// in NameTypes.h
// ...
class FName
{
    // ...
    FORCEINLINE bool operator==(FName Other) const
    {
    	return ToUnstableInt() == Other.ToUnstableInt();
    }
    
    FORCEINLINE bool operator!=(FName Other) const
    {
    	return !(*this == Other);
    }
    // ...
    
#if UE_FNAME_OUTLINE_NUMBER
    FORCEINLINE uint64 ToUnstableInt() const
    {
    	return ComparisonIndex.ToUnstableInt();
    }
#else
    FORCEINLINE uint64 ToUnstableInt() const
    {
        static_assert(STRUCT_OFFSET(FName, ComparisonIndex) == 0);
    	static_assert(STRUCT_OFFSET(FName, Number) == 4);
    	static_assert((STRUCT_OFFSET(FName, Number) + sizeof(Number)) == sizeof(uint64));

    	uint64 Out = 0;
    	FMemory::Memcpy(&Out, this, sizeof(uint64));
    	return Out;
    }
#endif

    //...
private:
	/** Index into the Names array (used to find String portion of the string/number pair used for comparison) */
	FNameEntryId	ComparisonIndex;
#if !UE_FNAME_OUTLINE_NUMBER
	/** Number portion of the string/number pair (stored internally as 1 more than actual, so zero'd memory will be the default, no-instance case) */
	uint32          Number;
#endif// ! //UE_FNAME_OUTLINE_NUMBER
#if WITH_CASE_PRESERVING_NAME
	/** Index into the Names array (used to find String portion of the string/number pair used for display) */
	FNameEntryId	DisplayIndex;
#endif // WITH_CASE_PRESERVING_NAME
    //...
}

 

assert 부분은 3가지로 되어있는데

1) FName의 ComparisonIndex의 offset이 0인지 체크

2) FName의 Number offset이 4인지 체크

3) ComparisonIndex + Number가 uint64 크기(8 바이트) 만큼을 차지하는지 확인

 

즉, FName은 8 byte가 ComparisionIndex(4 byte) + Number (4 byte)로 구성되어 있다는 뜻이다.

== 연산에서 FName을 uint64로 변환 후 비교하면 하위 4 byte의 ComparisonIndex로 비교하는 원리인 것으로 보인다.

 

2. FName::Compare()

CompareFloat = TestFName.Compare(OtherFName);

// in UnrealNames.cpp
int32 FName::Compare( const FName& Other ) const
{
    // ...
    // Names match, check whether numbers match.
    if (GetComparisonIndex() == Other.GetComparisonIndex())
    {
        return GetNumber() - Other.GetNumber();
    }

    // Names don't match. This means we don't even need to check numbers.
    return CompareDifferentIdsAlphabetically(GetComparisonIndex(), Other.GetComparisonIndex());
    //...
}

static int32 CompareDifferentIdsAlphabetically(FNameEntryId AId, FNameEntryId BId)
{
    checkSlow(AId != BId);

    FNamePool& Pool = GetNamePool();
    FNameBuffer ABuffer, BBuffer;
    FNameStringView AView =	Pool.Resolve(AId).MakeView(ABuffer);
    FNameStringView BView =	Pool.Resolve(BId).MakeView(BBuffer);

    // If only one view is wide, convert the ansi view to wide as well
    if (AView.bIsWide != BView.bIsWide)
    {
        FNameStringView& AnsiView = AView.bIsWide ? BView : AView;
        FNameBuffer& AnsiBuffer =	AView.bIsWide ? BBuffer : ABuffer;

    #ifndef WITH_CUSTOM_NAME_ENCODING
        FPlatformMemory::Memcpy(AnsiBuffer.AnsiName, AnsiView.Ansi, AnsiView.Len * sizeof(ANSICHAR));
        AnsiView.Ansi = AnsiBuffer.AnsiName;
    #endif

        ConvertInPlace<ANSICHAR, WIDECHAR>(AnsiBuffer.AnsiName, AnsiView.Len);
        AnsiView.bIsWide = true;
    }

    int32 MinLen = FMath::Min(AView.Len, BView.Len);
    if (int32 StrDiff = AView.bIsWide ?	FCStringWide::Strnicmp(AView.Wide, BView.Wide, MinLen) :
                                        FCStringAnsi::Strnicmp(AView.Ansi, BView.Ansi, MinLen))
    {
        return StrDiff;
    }

    return AView.Len - BView.Len;
}

Compare은 비교 값이 작으면 음수, 같으면 0, 크면 양수를 반환한다.

이때 ComparisonIndex로 같은 Names인지 체크하고 나머지 Number 비교를 한다.

만약 Names가 다르다면 알파벳 순서 비교를 통해 차이를 반환하는 것 같다.

 

 

1-3. 네임 테이블 검색

FName이 네임 테이블에 존재하는지 알고 싶지만, 테이블에 추가하기 싫은 경우에는 다음처럼 사용하면 된다.

if(FName(TEXT("pelvis"), FNAME_Find) != NAME_None )
{
    // Do something
}

 

2. FText

언리얼 엔진(UE)에서 텍스트 현지화를 위한 주요 컴포넌트는 FText 클래스입니다. 이 클래스는 다음 기능을 제공하여 텍스트 현지화를 지원하므로 모든 사용자 대상 텍스트는 이 클래스를 사용해야 합니다.
- 현지화된 텍스트 리터럴 생성
- (자리표시자 패턴에서 텍스트를 생성하기 위한) 텍스트 포매팅
- 숫자에서 텍스트 생성
- 날짜 및 시간에서 텍스트 생성
- 대소문자 표기와 같은 파생 텍스트 생성
FText 에는 현지화되지 않거나 '컬처 무관' 텍스트를 생성하는 AsCultureInvariant 함수(또는 INVTEXT 매크로)도 있습니다. 이는 외부 API의 플레이어 이름을 사용자 인터페이스에 표시할 수 있는 이름으로 변환하는 것과 같은 작업에 유용합니다. FText::GetEmpty()를 사용하거나 FText()만 사용하여 빈 FText를 만들 수 있습니다.

 

UI와 Localization에 주로 사용되는 스트링 클래스인 것으로 보인다.

2-1. 변환

FText <-> FString 변환이 가능하다.

그러나 FText에는 현지화 데이터와 연결된 문자열이 포함되어 있기 때문에, FString으로 변환할 때 데이터 손실을 주의해야 한다.

// FString -> FText (Culture Invariant)
// 현지화되지 않은 Culture Invariant한 FText 인스턴스 생성
TestHUDText = FText::AsCultureInvariant(*TestHUDString);

// FString -> FText
// 현지화되지 않은 FText 인스턴스 생성. 추후 FText 프로퍼티에 할당하면 현지화 가능
TestHUDText = FText::FromString(*TestHUDString);

// FName -> FText ( == FName -> FString -> FText)
TestHUDText = FText::FromName(TestHUDName);

// FText -> FString
TestHUDString = TestText.ToString();

 

2-2. 비교

FText 데이터는 단순한 문자열보다 더 복잡하기 때문에 == 연산자 등의 비교를 지원하지 않는다.

대신, 다른 비교 함수들로 비교가 가능하다.

 

2-2-1. EqualTo

FText는 FTextComparison::ETextComparisoinLevel 값을 사용해 비교 규칙에 따라 비교를 진행한다.

내부적으로는 FText -> FString으로 변환 후 비교한다.

// in TextComparison.h

namespace ETextComparisonLevel
{
	enum Type
	{
		Default,	// Locale-specific Default
		Primary,	// Base
		Secondary,	// Accent
		Tertiary,	// Case
		Quaternary,	// Punctuation
		Quinary		// Identical
	};
}
// in Text.h

bool FText::EqualTo(const FText& Other, const ETextComparisonLevel::Type ComparisonLevel) const
{
	return FTextComparison::EqualTo(ToString(), Other.ToString(), ComparisonLevel);
}

 

FTextComparison의 EqualTo는 FTextComparsion::CompareTo로 비교하며, 이는 다시 ICUText.cpp / LegacyText.cpp로 구현이 나뉘어 있다.

 

ICUText.cpp의 구현은 아래와 같은데, 궁금한 사람은 세부 구현 내용을 찾아보면 될 것 같다.

int32 FTextComparison::CompareTo( const FString& A, const FString& B, const ETextComparisonLevel::Type ComparisonLevel )
{
	const TSharedRef<const icu::Collator, ESPMode::ThreadSafe> Collator( FInternationalization::Get().GetCurrentLanguage()->Implementation->GetCollator(ComparisonLevel) );

	// Create an iterator for 'A' so that we can interface with ICU
	FStringView AView = A;
	UCharIterator ADisplayStringICUIterator;
	FICUTextCharacterIterator ADisplayStringIterator(AView);
	uiter_setCharacterIterator(&ADisplayStringICUIterator, &ADisplayStringIterator);

	// Create an iterator for 'B' so that we can interface with ICU
	FStringView BView = B;
	UCharIterator BDisplayStringICUIterator;
	FICUTextCharacterIterator BDisplayStringIterator(BView);
	uiter_setCharacterIterator(&BDisplayStringICUIterator, &BDisplayStringIterator);

	UErrorCode ICUStatus = U_ZERO_ERROR;
	const UCollationResult Result = Collator->compare(ADisplayStringICUIterator, BDisplayStringICUIterator, ICUStatus);

	return Result;
}

 

2-2-2. EqualToCaseIgnored

위의 EqualTo에서 ETextComparisonLevel 값을 Secondary로 지정하여 호출한다.

bool FText::EqualToCaseIgnored(const FText& Other) const
{
	return FTextComparison::EqualToCaseIgnored(ToString(), Other.ToString());
}

 

2-2-3. CompareTo

EqualTo와 마찬가지로 ETextComparisonLevel 값을 사용해 비교한다.
비교 후 알파벳 순 정렬 기준 더 작으면 음수, 동일하면 0, 더 크면 양수를 반환한다.

int32 FText::CompareTo(const FText& Other, const ETextComparisonLevel::Type ComparisonLevel) const
{
	return FTextComparison::CompareTo(ToString(), Other.ToString(), ComparisonLevel);
}

 

2-2-4. CompareToCaseIgnored

위의 CompareTo 에서 ETextComparisonLevel 값을 Secondary로 지정하여 호출한다.

int32 FText::CompareToCaseIgnored(const FText& Other) const
{
	return FTextComparison::CompareToCaseIgnored(ToString(), Other.ToString());
}

2-3. UI에서 사용

Slate 및 UMG에서의 텍스트 표시는 FText 사용을 권장하고 있다.

사용 예시는 아래와 같다.

// 텍스트를 포함할 새 FCanvasTextItem 인스턴스를 만듭니다.
FCanvasTextItem TextItem(FVector2D::ZeroVector, TestHUDText, BigFont, FLinearColor::Black);
// FCanvasTextItem에 텍스트를 추가합니다.
TextItem.Text = FText::Format(LOCTEXT("ExampleFText", "You currently have {0} health left."), CurrentHealth);
// FCanvas::DrawItem을 사용하여 화면에 텍스트를 그립니다.
Canvas->DrawItem(TextItem, 10.0f, 10.0f);

 

3. FString

FName이나 FText 와는 달리, FString 은 조작이 가능한 유일한 스트링 클래스입니다. 대소문자 변환, 부분문자열 발췌, 역순 등 사용가능한 메서드는 많습니다. FString 은 검색, 변경에 다른 스트링과의 비교도 가능합니다. 그러나 바로 그것이 FString 이 다른 불변의 스트링 클래스보다 비싸지는 이유입니다.

 

유일하게 조작이 가능하지만, 그만큼 비용을 잘 고려해서 구현이 필요하다. 주로 디버깅 테스트 출력 등의 용도로 쓰이는 것 같다.

 

3-1. 변환

FString <-> FName, FText가 가능하다.
마찬가지로 FText는 현지화 데이터 손실, FName은 대소문자 구분을 주의해야한다.

// From FString
// FString -> FName
// FName은 대소문자 구분이 없어 주의해야 한다.
TestHUDName = FName(*TestHUDString);

// FString -> FText
// 현지화 데이터 손실을 주의해야한다.
TestHUDText = FText::FromString(TestHUDString);

// To FString
// FName -> FString
// FName은 대소문자 구분이 없어 주의해야 한다.
TestHUDName = TestHUDText.ToString();

// FText -> FString
// 현지화 데이터 손실을 주의해야한다.
TestHUDString = TestHUDText.ToString();

 

추가로 숫자 및 기타 변수 <-> FString으로 변환이 가능하다.

변수 유형 스트링에서 변환 스트링 포맷
float FString::SanitizeFloat(FloatVariable);  
int FString::FromInt(IntVariable);  
bool InBool ? TEXT("true") : TEXT("false"); 'true' 또는 'false'
FVector VectorVariable.ToString(); 'X= Y= Z='
FVector2D Vector2DVariable.ToString(); 'X= Y='
FRotator RotatorVariable.ToString(); 'P= Y= R='
FLinearColor LinearColorVariable.ToString(); '(R=,G=,B=,A=)'
UObject (InObj != NULL) ? InObj->GetName() : FString(TEXT("None")); UObject FName

 

변수 유형 스트링에서 변환 참고
bool TestHUDString.ToBool();  
int FCString::Atoi(*TestHUDString);  
float FCString::Atof(*TestHUDString);  

 

3-2. 비교

== 연산자를 사용해서 FString // FString 비교나 FString // TCHAR*s 배열 비교가 가능하다.

내부적으로는 FString::Equals를 사용하며 ESearchCase enum을 통해 대소문자 비교를 할 건지 정할 수 있다.

// in UnrealString.h
// class: FString
UE_NODISCARD FORCEINLINE bool operator==(const FString& Rhs) const
{
    return Equals(Rhs, ESearchCase::IgnoreCase);
}

// in CString.h
/** Determines case sensitivity options for string comparisons. */
namespace ESearchCase
{
	enum Type
	{
		/** Case sensitive. Upper/lower casing must match for strings to be considered equal. */
		CaseSensitive,

		/** Ignore case. Upper/lower casing does not matter when making a comparison. */
		IgnoreCase,
	};
};

 

FString::Equals는 길이 먼저 비교 후 대소문자 구분에 따라 FCString::Strcmp, FCString::Stricmp로 비교를 진행한다.

// in UnrealString.h

/**
 * Lexicographically tests whether this string is equivalent to the Other given string
 * 
 * @param Other 	The string test against
 * @param SearchCase 	Whether or not the comparison should ignore case
 * @return true if this string is lexicographically equivalent to the other, otherwise false
 */
UE_NODISCARD FORCEINLINE bool Equals(const FString& Other, ESearchCase::Type SearchCase = ESearchCase::CaseSensitive) const
{
    int32 Num = Data.Num();
    int32 OtherNum = Other.Data.Num();

    if (Num != OtherNum)
    {
        // Handle special case where FString() == FString("")
        return Num + OtherNum == 1;
    }
    else if (Num > 1)
    {
        if (SearchCase == ESearchCase::CaseSensitive)
        {
            return FCString::Strcmp(Data.GetData(), Other.Data.GetData()) == 0; 
        }
        else
        {
            return FCString::Stricmp(Data.GetData(), Other.Data.GetData()) == 0;
        }
    }

    return true;
}

 

== 연산자 외에 <, >, <=, >= 등의 비교도 있으니 세부 구현 내용을 찾아보면 될 것 같다.

 

3-3. 검색

검색은 1) Conatins() 2) Find() 두 가지 방법이 있다.

두 방법 모두 FString에서 서브 스트링이 있는지 찾으며 ESearchCase(대소문자 구분), ESearchDir(검색 방향)을 지정할 수 있다.

 

3-3-1. Contains

Contains는 서브스트링을 찾았는지 여부를 true, false로 반환한다.

// Example
TestHUDString.Contains(TEXT("Test"), ESearchCase::CaseSensitive, ESearchDir::FromEnd);

Contains는 내부적으로 Find 함수를 호출해 사용한다.

// in UnrealString.h
// Class: FString

/** 
 * Returns whether this string contains the specified substring.
 *
 * @param SubStr			Text to search for
 * @param SearchCase		Indicates whether the search is case sensitive or not ( defaults to ESearchCase::IgnoreCase )
 * @param SearchDir			Indicates whether the search starts at the beginning or at the end ( defaults to ESearchDir::FromStart )
 * @return					Returns whether the string contains the substring. If the substring is empty, returns true.
 **/
UE_NODISCARD FORCEINLINE bool Contains(const TCHAR* SubStr, ESearchCase::Type SearchCase = ESearchCase::IgnoreCase,
    ESearchDir::Type SearchDir = ESearchDir::FromStart) const
{
    return Find(SubStr, SearchCase, SearchDir) != INDEX_NONE;
}

 

3-3-2. Find

Find는 처음 찾은 서브스트링 인덱스를 반환한다.

검색을 시작할 인덱스를 지정할 수도 있으며, 찾지 못하는 경우 -1를 반환한다.

// Example
TestHUDString.Find(TEXT("test"), ESearchCase::CaseSensitive, ESearchDir::FromEnd, 10);
// in UnrealString.h
// Class: FString

/**
 * Searches the string for a substring, and returns index into this string of the first found instance. Can search
 * from beginning or end, and ignore case or not. If substring is empty, returns clamped StartPosition.
 *
 * @param SubStr			The string array of TCHAR to search for
 * @param StartPosition		The start character position to search from.  See note below.
 * @param SearchCase		Indicates whether the search is case sensitive or not
 * @param SearchDir			Indicates whether the search starts at the beginning or at the end.
 */
UE_NODISCARD int32 Find(const TCHAR* SubStr, ESearchCase::Type SearchCase = ESearchCase::IgnoreCase,
    ESearchDir::Type SearchDir = ESearchDir::FromStart, int32 StartPosition = INDEX_NONE) const
{
    return SubStr ? Find(SubStr, FCString::Strlen(SubStr), SearchCase, SearchDir, StartPosition) : INDEX_NONE;
}

 

Find 내부 구현을 보면, End -> Start 탐색은 브루트포스로 처리하는 것을 볼 수가 있다.

Start -> End 탐색은 FCString::Strnsrt(Strnistr if CaseSensitive)에 위임한다.

// in String.cpp

int32 FString::Find(const TCHAR* SubStr, int32 SubStrLen, ESearchCase::Type SearchCase, ESearchDir::Type SearchDir, int32 StartPosition) const
{
	checkf(SubStrLen >= 0, TEXT("Invalid SubStrLen: %d"), SubStrLen);

	if (SearchDir == ESearchDir::FromStart)
	{
		const TCHAR* Start = **this;
		int32 RemainingLength = Len();
		if (StartPosition != INDEX_NONE && RemainingLength > 0)
		{
			const TCHAR* End = Start + RemainingLength;
			Start += FMath::Clamp(StartPosition, 0, RemainingLength - 1);
			RemainingLength = UE_PTRDIFF_TO_INT32(End - Start);
		}
		const TCHAR* Tmp = SearchCase == ESearchCase::IgnoreCase
			? FCString::Strnistr(Start, RemainingLength, SubStr, SubStrLen)
			: FCString::Strnstr(Start, RemainingLength, SubStr, SubStrLen);

		return Tmp ? UE_PTRDIFF_TO_INT32(Tmp-**this) : INDEX_NONE;
	}
	else
	{
		// if ignoring, do a onetime ToUpper on both strings, to avoid ToUppering multiple
		// times in the loop below
		if ( SearchCase == ESearchCase::IgnoreCase)
		{
			return ToUpper().Find(FString(SubStrLen, SubStr).ToUpper(), ESearchCase::CaseSensitive, SearchDir, StartPosition);
		}
		else
		{
			const int32 SearchStringLength=FMath::Max(1, SubStrLen);
			
			if (StartPosition == INDEX_NONE || StartPosition >= Len())
			{
				StartPosition = Len();
			}
			
			for (int32 i = StartPosition - SearchStringLength; i >= 0; i--)
			{
				int32 j;
				for (j=0; j != SubStrLen; j++)
				{
					if ((*this)[i+j]!=SubStr[j])
					{
						break;
					}
				}
				
				if (j == SubStrLen)
				{
					return i;
				}
			}
			return INDEX_NONE;
		}
	}
}

 

FCString::Strnistr 내부 구현을 살펴보면 마찬가지로 브루트포스 방식으로 처리됨을 확인할 수 있다.

// in CString.h

template <typename T>
const typename TCString<T>::CharType* TCString<T>::Strnistr(const CharType* Str, int32 InStrLen, const CharType* Find, int32 FindLen)
{
	if (FindLen <= 0)
	{
		checkf(FindLen >= 0, TEXT("Invalid FindLen: %d"), FindLen);
		return Str;
	}
	if (InStrLen < FindLen)
	{
		checkf(InStrLen >= 0, TEXT("Invalid InStrLen: %d"), InStrLen);
		return nullptr;
	}

	// get upper-case first letter of the find string (to reduce the number of full strnicmps)
	CharType FindInitial = TChar<CharType>::ToUpper(*Find);
	// Set FindSuffix,FindSuffixLength to the characters of Find after the first letter
	int32 FindSuffixLength = FindLen - 1;
	const CharType* FindSuffix = Find + 1;

	// while the length of the remaining string is >= FindLen
	const CharType* StrLastChance = Str + InStrLen - FindLen;
	while (Str <= StrLastChance)
	{
		CharType StrChar = *Str++;

		// make sure it's upper-case
		StrChar = TChar<CharType>::ToUpper(StrChar);
		// if it matches the first letter of the find string, do a case-insensitive string compare for the length of the find string
		if (StrChar == FindInitial && !Strnicmp(Str, FindSuffix, FindSuffixLength))
		{
			// if we found the string, then return a pointer to the beginning of it in the search string
			return Str - 1;
		}
	}

	// if nothing was found, return nullptr
	return nullptr;
}

 

FString 비교 시 성능이 중요한 경우 KMP 등의 문자열 처리 알고리즘을 추가로 구현할 필요가 있어보인다.

 

3.4. 접합

FString에 FString을 더할 수 있으며, +=과 + 연산자로 가능하다.

// += 연산자
StringResult += AddedString;

// + 연산자
StringResult = AddedString1 + AddedString2;

 

+= 내부 구현은 ApeendChars 함수를 호출해 진행되고 있다.

FString이 TCHAR* 배열로 구현되어 있어 FString 추가 역시 CHAR 배열에 글자를 추가하는 방식으로 작성되어 있다.

// in UnrealString.h

/** Append a string and return a reference to this */
template <typename StrType>
FORCEINLINE auto operator+=(StrType&& Str) -> decltype(Append(Forward<StrType>(Str)))
{
    return Append(Forward<StrType>(Str));
}

// in String.cpp
void FString::AppendChars(const ANSICHAR* Str, int32 Count)
{
	CheckInvariants();
	AppendCharacters(Data, Str, Count);
}

template<typename CharType>
void AppendCharacters(TArray<TCHAR>& Out, const CharType* Str, int32 Count)
{
	check(Count >= 0);

	if (!Count)
	{
		return;
	}

	checkSlow(Str);

	int32 OldEnd = Out.Num();
	
	// Try to reserve enough space by guessing that the new length will be the same as the input length.
	// Include an extra gap for a null terminator if we don't already have a string allocated
	Out.AddUninitialized(Count + (OldEnd ? 0 : 1));
	OldEnd -= OldEnd ? 1 : 0;

	TCHAR* Dest = Out.GetData() + OldEnd;

	// Try copying characters to end of string, overwriting null terminator if we already have one
	TCHAR* NewEnd = FPlatformString::Convert(Dest, Count, Str, Count);
	if (!NewEnd)
	{
		// If that failed, it will have meant that conversion likely contained multi-code unit characters
		// and so the buffer wasn't long enough, so calculate it properly.
		int32 Length = FPlatformString::ConvertedLength<TCHAR>(Str, Count);

		// Add the extra bytes that we need
		Out.AddUninitialized(Length - Count);

		// Restablish destination pointer in case a realloc happened
		Dest = Out.GetData() + OldEnd;

		NewEnd = FPlatformString::Convert(Dest, Length, Str, Count);
		checkSlow(NewEnd);
	}
	else
	{
		int32 NewEndIndex = (int32)(NewEnd - Dest);
		if (NewEndIndex < Count)
		{
			Out.SetNumUninitialized(OldEnd + NewEndIndex + 1, /*bAllowShrinking=*/false);
		}
	}

	// (Re-)establish the null terminator
	*NewEnd = '\0';
}
// CHAR* 타입에 따라 ANSICHAR*, WIDECHAR*, UCS2CHAR*, UTF8CHAR*로 각각 구현되어 있음.

 

 

3-5. Printf

C에서 자주 쓰던 Printf는 언리얼에서 FString::Printf로 쓸 수 있다.

디버깅 메시지로 자주 사용하며 아래 예시처럼 작성한다.

FString AShooterHUD::GetTimeString(float TimeSeconds)
{
    // 분과 초만 관련이 있습니다.
    const int32 TotalSeconds = FMath::Max(0, FMath::TruncToInt(TimeSeconds) % 3600);
    const int32 NumMinutes = TotalSeconds / 60;
    const int32 NumSeconds = TotalSeconds % 60;

    const FString TimeDesc = FString::Printf(TEXT("%02d:%02d"), NumMinutes, NumSeconds);
    return TimeDesc;
}

 

참고 사이트

더보기

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/string-handling-in-unreal-engine?application_version=5.3

 

언리얼 엔진의 스트링 처리 | 언리얼 엔진 5.3 문서 | Epic Developer Community

FName, FText, FString에 대한 레퍼런스 가이드와 언리얼 엔진에서 사용할 수 있는 문자열 클래스에 대한 개요입니다.

dev.epicgames.com

 

FName

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/fname-in-unreal-engine?application_version=5.3

 

언리얼 엔진의 FName | 언리얼 엔진 5.3 문서 | Epic Developer Community

언리얼 엔진에서 FName 제작, 변환 및 비교를 위한 참고 자료입니다.

dev.epicgames.com

 

FText

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/ftext-in-unreal-engine?application_version=5.3

 

언리얼 엔진의 FText | 언리얼 엔진 5.3 문서 | Epic Developer Community

언리얼 엔진의 FText를 통한 생성, 변환, 비교 등에 대한 레퍼런스입니다.

dev.epicgames.com

 

FString

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/fstring-in-unreal-engine?application_version=5.3

저작자표시 변경금지 (새창열림)

'게임개발 > Unreal Engine' 카테고리의 다른 글

[UE5] 언리얼의 Multi-threading  (0) 2026.02.16
[UE5] Replicate Montage Multicast in C++ not working  (0) 2025.03.01
[UE5] C++ AActor::Destroy() not working in BeginPlay()  (0) 2025.02.06
[UE5] Unreal Engine C++ API References  (2) 2024.08.20
[UE5] Root Motion with custom mesh not working  (0) 2024.07.17
'게임개발/Unreal Engine' 카테고리의 다른 글
  • [UE5] 언리얼의 Multi-threading
  • [UE5] Replicate Montage Multicast in C++ not working
  • [UE5] C++ AActor::Destroy() not working in BeginPlay()
  • [UE5] Unreal Engine C++ API References
깜냥c
깜냥c
게임 개발/클라이언트/AI/PS/기타 연구
  • 깜냥c
    Choice Program
    깜냥c
  • 전체
    오늘
    어제
    • 분류 전체보기 (62) N
      • 언어 (12)
        • C,C++ (10)
        • C# (1)
        • Python (1)
      • PS (20)
        • 백준 문제 (19)
        • 알고리즘 (1)
      • 인공지능 (2)
      • 게임제작 (7)
      • 게임개발 (18) N
        • Unity (9)
        • Unreal Engine (7) N
        • Godot Engine (1)
      • 기타 (2)
  • 블로그 메뉴

    • 홈
    • 방명록
    • 블로그 소개
  • 링크

    • 김병장의 IT 블로그
    • 식품영양과 데이터사이언스
  • 공지사항

  • 인기 글

  • 태그

    Unreal
    입출력
    백준
    C++
    BOJ
    C언어
    배낭 문제
    UE5
    unity
    Godot
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
깜냥c
[UE5] FName, FText, FString
상단으로

티스토리툴바