我参与了您尝试生成尽可能小的二进制文件的挑战之一,因此我正在构建我的程序没有 C 或 C++ 运行时库 (RTL)。我没有链接到 DLL 版本或静态版本。我什至没有 #include
头文件。我有这个工作正常。
一些 RTL 函数,例如 memset()
,可能很有用,所以我尝试添加自己的实现。它在 Debug 版本中运行良好(即使对于那些编译器生成对 memset()
的 implicit 调用的地方)。但是在发布版本中,我收到一条错误消息,说我无法定义内在函数。你看,在 Release 版本中,内部函数被启用,并且 memset()
是一个内部函数。
我很想在我的发布版本中使用 memset()
的内在函数,因为它可能是内联的,并且比我的实现更小、更快。但我似乎是第 22 条军规中的一员。如果我没有定义 memset()
,链接器会提示它未定义。如果我定义了它,编译器会提示我无法定义一个内在函数。
有谁知道定义、声明、#pragma
以及编译器和链接器标志的正确组合,以便在不增加 RTL 开销的情况下获得内在函数?
Visual Studio 2008、x86、Windows XP+。
让问题更具体一点:
extern "C" void * __cdecl memset(void *, int, size_t);
#ifdef IMPLEMENT_MEMSET
void * __cdecl memset(void *pTarget, int value, size_t cbTarget) {
char *p = reinterpret_cast<char *>(pTarget);
while (cbTarget > 0) {
*p++ = static_cast<char>(value);
--cbTarget;
}
return pTarget;
}
#endif
struct MyStruct {
int foo[10];
int bar;
};
int main() {
MyStruct blah;
memset(&blah, 0, sizeof(blah));
return blah.bar;
}
我是这样构建的:
cl /c /W4 /WX /GL /Ob2 /Oi /Oy /Gs- /GF /Gy intrinsic.cpp
link /SUBSYSTEM:CONSOLE /LTCG /DEBUG /NODEFAULTLIB /ENTRY:main intrinsic.obj
如果我使用 memset()
的实现进行编译,我会收到编译器错误:
error C2169: 'memset' : intrinsic function, cannot be defined
如果我在没有实现 memset()
的情况下编译它,我会收到链接器错误:
error LNK2001: unresolved external symbol _memset
最佳答案
我想我终于找到了解决办法:
首先,在头文件中,使用 pragma 声明 memset()
,如下所示:
extern "C" void * __cdecl memset(void *, int, size_t);
#pragma intrinsic(memset)
这允许您的代码调用 memset()
。大多数情况下,编译器会内联内部版本。
其次,在一个单独的实现文件中,提供一个实现。防止编译器提示重新定义内部函数的技巧是首先使用另一个 pragma。像这样:
#pragma function(memset)
void * __cdecl memset(void *pTarget, int value, size_t cbTarget) {
unsigned char *p = static_cast<unsigned char *>(pTarget);
while (cbTarget-- > 0) {
*p++ = static_cast<unsigned char>(value);
}
return pTarget;
}
这为优化器决定不使用内部版本的情况提供了一种实现。
突出的缺点是您必须禁用整个程序优化(/GL 和/LTCG)。我不确定为什么。如果有人找到一种方法可以在不禁用全局优化的情况下做到这一点,请加入。
关于c++ - 如何使用没有运行时库的 VC++ 内部函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2938966/