How do I cast an FString to TCHAR array?

I’m trying to cast FString into TCHAR array. As for simple use case lets consider using it in UE_LOG:

MyPlayerController.h

UCLASS()
class AMyPlayerController : public APlayerController
{	
	(... public class definition)
	
	UFUNCTION( EXEC )
	void Proof( FString ClassName );
}

MyPlayerController.cpp

void AMyPlayerController::Proof( FString ClassName )
{
	UE_LOG( LogActor, Error, *(ClassName) );
}

Error which complier throws me is:

Error	1	error C2338: Formatting_string_must_be_a_TCHAR_array

According to similar question it should work. Am I doing something wrong and missing something?

I’m aware that in this particular case I could happily live with:

UE_LOG( LogActor, Error, TEXT( "%s" ), *(ClassName) );

But it does not solves the issue.

1 Like

Hi sick. I was able to get this to compile without any errors by using the following:

UE_LOG(LogActor, Error, TEXT("%s"), *ClassName);

Are you still getting an error message when you use that syntax?

EDIT You might also take a look here for details on outputting strings to logs.

1 Like

Thanks , however it will not solve the problem : ( look at second part of my answer, i was aware of this solution, but it’s a workaround.

I’ve also been going through linked docs, but i did not found there answer for this problem.

1 Like

#Re Compile

Using only this

UE_LOG( LogActor, Error, TEXT( "%s" ), *ClassName );

in every case

can you recompile and send us your error message?

Make sure to triple check the line numbers and classes involved in this in case you didnt check something accurately. The above code should work.

Hi sick. I spent some time exploring the source code, and it appears that the syntax format I mentioned above is the standard used throughout the source code. I am not sure if there is a way to avoid using the TEXT() macro entirely, but that does not appear to be the case.

I was aware of this solution : ( thanks for help though

There are few encoding conversion macros available AFAIK, there should be something like ANSI_TO_TCHAR among them, it would work for you to avoid TEXT() macro.

Beside using in terms of UE_LOG, is there an way to actually convert FString into TCHAR?

Hi, sick. Try this:

FString MyString;

MyString.GetCharArray();

MyString.GetCharArray().GetData();

1 Like

Hi everyone,

In the time since this post was first made, I have picked up a few more details about FStrings. If you simply need to convert an FString into TCHAR, you can do so by dereferencing the FString. For example, something like this would work: const TCHAR* TheMessage = *TheString;

However, as was noted in this post, that will not work within the UE_LOG macro. The reason for this is that the UE_LOG macro requires a string literal. The TEXT macro provides the literal, so it has to be used in this instance. Allowing an arbitrary string to be used in the UE_LOG macro can open a potential security hole.

I think you can overcome that problem with:
UE_LOG(Debug, Log, TEXT("%s"), *myFString);

works for me,thxs.

What workaround would you suggest if the formatting string is a variable rather than a string literal? For example, if you want to use the same formatting string in several places like this case (which now gives a warning):

FString directory = "/Game/Path/ToFile/%s";
FString path = FString::Printf(*directory, TEXT("file.txt"));

Thank you, Tim_C! This was of great help.

@iandallas

In such case you can try:

    FString FormattedErrorMessage;
    if (ErrorMessage.Len() > 0)
    {
        int32 Size = snprintf(nullptr, 0, TCHAR_TO_UTF8(*ErrorMessage), \* your variables here*\) + 1;
        char* Buffer = new char[Size];
        snprintf(Buffer, Size, TCHAR_TO_UTF8(*ErrorMessage),  \* your variables here*\);
        FormattedErrorMessage = FString(UTF8_TO_TCHAR(Buffer));
        delete[] Buffer;
    }

    UE_LOG(LogTemp, Error, TEXT("%s"), *FormattedErrorMessage);

If the reason you don’t want to use the workaround is that you are sending a format string, and you want to follow the FString with formated vairables. Then what you would need is:

    FString FormattedErrorMessage;
    if (ErrorMessage.Len() > 0)
    {
        int32 Size = snprintf(nullptr, 0, TCHAR_TO_UTF8(*ErrorMessage), \* your variables here*\) + 1;
        char* Buffer = new char[Size];
        snprintf(Buffer, Size, TCHAR_TO_UTF8(*ErrorMessage),  \* your variables here*\);
        FormattedErrorMessage = FString(UTF8_TO_TCHAR(Buffer));
        delete[] Buffer;
    }

    UE_LOG(LogTemp, Error, TEXT("%s"), *FormattedErrorMessage);

This will also work with a variadic template if that’s what you are looking for. That’s how I stumbled on this thread.
in such chase just paste std::forward(args)… into * your variables here*
For example I used it to create myself a template that encapsulates Timeout checking and error loging into a single template call:

template<typename... Args>
static bool OnTimeout_helper(float MaxTime, FDateTime StartTime, const FString& ErrorMessage, Args&&... args)
{
    if ((FDateTime::Now() - StartTime).GetTotalSeconds() <= MaxTime)
    {
        return false;
    }

    FString FormattedErrorMessage;
    if (ErrorMessage.Len() > 0)
    {
        int32 Size = snprintf(nullptr, 0, TCHAR_TO_UTF8(*ErrorMessage), std::forward<Args>(args)...) + 1;
        char* Buffer = new char[Size];
        snprintf(Buffer, Size, TCHAR_TO_UTF8(*ErrorMessage), std::forward<Args>(args)...);
        FormattedErrorMessage = FString(UTF8_TO_TCHAR(Buffer));
        delete[] Buffer;
    }

    UE_LOG(LogTemp, Error, TEXT("%s"), *FormattedErrorMessage);
    return true;
}