UE4.27, 揣摩源码, 小展 "宏" 图
ue宏乃催眠神器,睡不着就点进来看看罢
1. CORE_API
见PCH_Core.h有(PCH=Pre-Compiled Header)
#define CORE_API DLLEXPORT
事实上,有许多名为 XXXXXX_API的宏 被定义为DLLEXPORT或DLLIMPORT
好了,现在一个问题变成俩了
2. DLLEXPORT, DLLIMPORT
如果你的分词功能和我一样被这个大写整懵了,它其实是这个意思
dll Export和dll Import
顾名思义是影响 动态链接库(dll)的导出和导入的
找找它的定义
喜闻乐见的多平台又来了
咱们装作看不见别的,点开windows版本,额等等
这里的 i 是大写诶,是彩蛋吗?()
点进windows版本
这两个关键字的组合是什么意思呢?
查阅网络后,后者的作用更容易生效。在编译的时候可以减少不必要的指令(如trunk)的生成,减少指令数目从而优化性能
而前者的作用,我就只是贴在这吧。如果将类标记为 __declspec(dllexport)
,则类层次结构中类模板的任何专用化都将隐式标记为 __declspec(dllexport)
。 这意味着类模板将进行显式实例化,且必须定义类的成员
3. TEXT
std::string str1 = "chen"; // IDE默认的字符串
std::wstring str2 = L"chen"; // wchar_t字符串(宽字符)
// ??? str3 = u8"chen"; // utf-8字符串
std::u16string str3 = u"chen"; // char16_t字符串
std::u32string str4 = U"chen"; // char32_t字符串
检索该宏
windows里的TEXT定义,实际是L##quote,实际上就是把默认字符串变成宽字符字符串
而UE里是这样的
UE_BUILD_DOCS是UBT控制的,感谢UBT,我们可以暂时不理会它,将该宏认为 0 即可
而PLATFORM_TCHAR_IS_CHAR16就有意思了,右键查找后是这样的
(HAL是Hardware Abstraction Layer硬件抽象层的缩写)
我们可以看到,出于平台兼容性的考量,默认将tchar设置为wchar_t (字符串前链接L)
(windows里 TCHAR 可以根据编译选项被定义为 char 或 wchar_t)
而在unix,ios,mac,android里认为tchar就是char16 (因此链接u)
4. CHECK_PUREVIRTUALS, PURE_VIRTUAL
#if CHECK_PUREVIRTUALS
#define PURE_VIRTUAL(func,...) =0;
#else
#define PURE_VIRTUAL(func,...) { LowLevelFatalError(TEXT("Pure virtual not implemented (%s)"), TEXT(#func)); __VA_ARGS__ }
#endif
神奇的思路。因为约定里,PURE_VIRTUAL是表征该类成员函数是纯虚函数,而实际上是个正常运行的函数,仅在调用时呼出错误报告。
为什么要如此设定?因为当引擎 PreInit 时,会为每个UObject的派生类实例化以创建CDO对象,而一旦它真的包含了语法上的=0函数,即纯虚函数,它就是一个抽象类,是不能实例化的。
那怎么办呢?纯虚函数语法的应用效果其实是让该类的子类一定要重写这个函数,PURE_VIRTUAL宏虽然不能完成这个功能,但是可以在该函数未如期望重写又被调用的敏感状况下报错,
这样一来,至少可以保证(伪)纯虚函数在(可能的)子类重写函数后的应用上更贴近预期。
而CHECK_PUREVIRTUALS被UBT控制,假如UBT要求检查纯虚函数,该宏被拓展为=0即忽地变成了纯虚函数的语法,CDO创建时必定出错,错误时的报错地点就可以视作TODO的一部分,以期待改进。
不禁感叹UE的宏设计真的妙极。
5. FORCEINLINE, FORCENOINLINE
编译平台相关宏,WindowsPlatform.h里如下定义
#define FORCEINLINE __forceinline /* Force code to be inline */
#define FORCENOINLINE __declspec(noinline) /* Force code to NOT be inline */
事实上,inline,__inline是建议内联,是否内联由编译器自己进行分析。
而__forceinline是强烈建议内联,但仍不绝对内联。因为存在一些不能内联的情景。假如使用了又实际上没有内联,编辑器会发出警告。
__declspec(noinline)是禁止内联。
6. PLATFORM_LITTLE_ENDIAN
可以观察到,寻常的平台都是小端模式
0x12345678
多字节数据,小端模式,几个字节逆内存序读出组成原数据。
多字节数据,大端模式,几个字节顺内存序读出组成原数据。
7. UE_SERVER, WITH_SERVER_CODE
UE_SERVER 检查它是否是Server-Build
WITH_SERVER_CODE 检查此构建是否允许使用服务器 (上才会用到的) 代码,例如:
Game: UE_SERVER=0,WITH_SERVER_CODE=1
Server:UE_SERVER=1,WITH_SERVER_CODE=1
Client: UE_SERVER=0,WITH_SERVER_CODE=0
8. DECLARE_STATS_GROUP, DECLARE_CYCLE_STAT, SCOPE_CYCLE_COUNTER
UE的性能分析工具之一,埋点计时
DECLARE_STATS_GROUP // 自定义Stat群组
DECLARE_CYCLE_STAT // 自定义埋点
SCOPE_CYCLE_COUNTER // 放在一个函数体的内部顶端,监听该函数的调用次数和耗时
9. assets
check / checkslow // 表达式为false时,停止执行,USE_CHECKS_IN_SHIPPING宏可以改变check,使其在发布版本shipping中不再被忽略
checkf / checkfslow // f表示可以跟format字符串表示,这些信息将在条件成立后,输出日志信息
// slow表示仅作用于Debug版本
verify / verifyslow // verify的表达式将总是被执行,check在发布版本连带着表达式被忽略
verifyf / verifyfslow
10. PRAGMA_DISABLE_DEPRECATION_WARNINGS, PRAGMA_ENABLE_DEPRECATION_WARNINGS, UE_DEPRECATED
#define PRAGMA_DISABLE_DEPRECATION_WARNINGS \
__pragma (warning(push)) \
__pragma (warning(disable: 4995)) /* 'function': name was marked as #pragma deprecated */ \
__pragma (warning(disable: 4996)) /* The compiler encountered a deprecated declaration. */
#define PRAGMA_ENABLE_DEPRECATION_WARNINGS \
__pragma (warning(pop))
以下是使用的例子
PRAGMA_DISABLE_DEPRECATION_WARNINGS
ActorInfo->LastNetUpdateTime = ElapsedTime;
PRAGMA_ENABLE_DEPRECATION_WARNINGS