我有这个函数可以用 N 字节的重复模式填充缓冲区。
void* memsetPattern(void* buf, size_t bufSize, const void* Pattern, size_t PatternSize) {
if (buf == nullptr || Pattern == nullptr || PatternSize == 0) { return nullptr; }
if (bufSize == 0) { return buf; } // 0 Bytes to copy
if (PatternSize == 1) {
memset(buf, ((uint8_t*)Pattern)[0], bufSize);
return buf;
}
/* otherwise, if PatternSize >= 2 */
}
如果 PatternSize 是 1 个字节,该函数将改为运行
memset(buf, ((uint8_t*)Pattern)[0], bufSize)
,因为 memset 的运行速度比我的函数稍快。
如果用户想调用
memsetPattern(buf, bufSize, Pattern, 1)
,是否可以直接调用(Pattern != nullptr && buf != nullptr) ? memset(buf, ((uint8_t*)Pattern)[0], bufSize) : nullptr
,因为在编译时PatternSize等于1字节?
我想一种方法是使用宏,但感觉不对。
#define memsetPattern_Macro(buf, bufSize, Pattern, PatternSize) \
(PatternSize == 1) ? ( \
(Pattern != nullptr && buf != nullptr) ? memset(buf, ((uint8_t*)Pattern)[0], bufSize) : nullptr \
) : memsetPattern(buf, bufSize, Pattern, PatternSize)
环顾四周,我确实找到了
if constexpr ()
,但是当我尝试if constexpr (PatternSize == 1) {
时,它给出了错误,因为'PatternSize' is not a constant expression
。
我应该如何根据编译时已知的参数来切换函数?我需要更改传递给 memsetPattern() 函数的参数类型吗?
如果用户想要调用
,是否可以直接调用memsetPattern(buf, bufSize, Pattern, 1)
,因为在编译时已知(Pattern != nullptr && buf != nullptr) ? memset(buf, ((uint8_t*)Pattern)[0], bufSize) : nullptr
等于1个字节?PatternSize
是的,这正是您已经在做的事情。 任何优化编译器都已经内联函数,然后利用已知常量,例如
Pattern
始终为 1
。
例如,如果您编写以下内容:
void* foo(void* buf, size_t bufSize, const void* Pattern) {
return memsetPattern(buf, bufSize, Pattern, 1);
}
...然后 GCC 将其优化为(https://godbolt.org/z/W16E6ffee):
foo(void*, unsigned long, void const*):
test rdi, rdi
je .L17
test rdx, rdx
je .L17
test rsi, rsi
je .L22
sub rsp, 8
movzx eax, BYTE PTR [rdx]
mov rdx, rsi
mov esi, eax
call memset
...
无条件调用
memset
之前的唯一分支是测试 buf
、Pattern
或 bufSize
是否为零/空。 PatternSize == 1
和 PatternSize == 0
的测试已完全删除。
您之前可能已经被告知:不要过早优化。对你的编译器有信心。