UE -- TCHAR与TEXT宏

UE -- TCHAR与TEXT宏

前言:字符编码基本知识

​ 计算机的世界,所有信息都是0/1组合的二进制序列。 要想让字符能被计算机识别,必须经过编码 。如何让大家按相同的规则,规定好字符与二进制序列之间的对应关系呢,这就是字符集的作用了(如A对应01000001,字符集是ASCII码)。容易搞混的是字符集与字符编码的区别,如Unicode和UTF的区别。

​ 首先字符编码的作用是 规定如何编码及存储这些字符对应的二进制序列 (你规定了A对应01000001但不代表计算机一定要按照字符对应的数字将数字本身直接存储)。简单理解就是 字符集是一种协议,而字符编码是对字符集的一种实现。 既然称之为“实现”,也说明对同一种字符集可能有不同的编码方式。

字符集的演变及相应字符编码

​ ASCII => ANSI(本地化,如中文的GBK) => Unicode(国际化,大一统)

​ ASCII即表示一种字符集,也代表一种字符编码(直接将字符对应的8位二进制数作为最终形式存储)。即常说的”ASCII编码“。

​ ANSI体系的字符集如GB2312、GBK,也是即表示一种字符集,也代表一种字符编码。

​ Unicode所规定字符集称为Universal Character Set(UCS),Unicode分为UCS-2和UCS-4,分别是2字节和4字节,实际2字节就够用了。对应的字符编码有UTF-8,UTF-16,UTF-32,其中UTF-8应用广泛。

注意: 要从“环境/终端/文本/程序”等不同层次去理解编码,并尝试解决遇到的问题

更加详细的了解请至下方相应参考资料 ,接下来言归正传,回到TCHAR与TEXT宏。

一、TCHAR的作用

​ 首先在C++中基本数据类型中表示字符的有两种: char wchar_t 。对应的字符集分别是 ANSI (本地化,在简体中文系统下,代表 GB2312 编码)与 Unicode (国际化)。在不同平台环境下(PC、PS4),我们可能需要不同的字符类型。

TCHAR就是UE4对char和wchar_t的封装 ,将其中的操作进行了统一,使程序具有可移植性。

TCHAR通常被定义为一种变量类型,如果在编译器中使用的是Unicode,则TCHAR解析为wchar_t。反之,则TCHAR解析为char。

​ FString 本质是构建在TArray<TCHAR> 之上,即字符串的元素使用TCHAR类型而非char类型。







二、TEXT宏的作用

​ 在UE的字符串的编码规范中,字符串字面量周围 必须使用 TEXT() 宏 :若未使用,将使用 ANSI 对文字进行编码,可能会导致支持字符高度受限,构建 FStrings 的代码将导致不理想的字符转换过程。其原因就在于无包裹的字符串字面量默认就是表示ANSI字符,字符串字面量前面多个L就是表示宽字符, 通过TEXT包裹则可以让UE4自动选择适合当前平台环境的编码 (例如宏可能展开成L"Hello World!"也可能展开成u“Hello World!”)

当编译器设置为在Unicode上运行时,它会将包含的文本升级为Unicode(在前面加上前缀L)

"Hello World!";              //ANSI字符  strlen("Hello") = 5; 
L"Hello World!";            //16位宽字符(unicode字符串,一个字符占两个字节) strlen(L"Hello") = 10;  
TEXT("Hello World!");       //具有可移植性,在部分平台是16位宽字符,传入 FString 的 ANSI 文字完成到 TCHAR 的转换(本地万国码编码)
//这样我们可以用TCHAR*表示这种字符串
const TCHAR* TcharString = TEXT("Hello World!");

三、虚幻使用的文本文件

​ 所有TCHAR字符都可以用单字节表示的字符串将存储为一串8位字节,否则存储为UTF-16,除非传递了值为true的bAlwaysSaveAsAnsi,在这种情况下,字符串将先转换为默认的Windows编码。该操作当前仅对着色器文件执行,以解决着色器编译器在处理UTF-16文件时存在的问题。

​ 当我们调用UE4以外的API必须得将TCHAR类型与char/wchar_t类型相互转换时,就要使用UE4提供的转换宏。

// 引擎字符串(TCHAR*) -> ANSI字符串(char*)
TCHAR_TO_ANSI(TcharString);
// 引擎字符串(TCHAR*) -> Unicode字符串(wchar_t*)
TCHAR_TO_UTF8(TcharString);
// ANSI字符串(char*) -> 引擎字符串(TCHAR*)
ANSI_TO_TCHAR(CharString);
// Unicode字符串(wchar_t*) -> 引擎字符串(TCHAR*)
UTF8_TO_TCHAR(WChartString);

​ UE4提供了相应的助手类

typedef TStringConversion<TCHAR,ANSICHAR,FANSIToTCHAR_Convert> FANSIToTCHAR;
typedef TStringConversion<ANSICHAR,TCHAR,FTCHARToANSI_Convert> FTCHARToANSI;
typedef TStringConversion<ANSICHAR,TCHAR,FTCHARToUTF8_Convert> FTCHARToUTF8;
typedef TStringConversion<TCHAR,ANSICHAR,FUTF8ToTCHAR_Convert> FUTF8ToTCHAR;
// 如果您需要知道所产生字符串的字节长度,可以使用助手类,而不是宏。例如:
FString String;