如何使用VC++;不带运行时库的内部函数 我参与了其中的一个挑战,在这里你尝试生成最小可能的二进制,所以我在没有C或C++运行时库(RTL)的情况下构建我的程序。我没有链接到DLL版本或静态版本。我甚至不包括头文件。我的这个很好用
一些RTL函数,如如何使用VC++;不带运行时库的内部函数 我参与了其中的一个挑战,在这里你尝试生成最小可能的二进制,所以我在没有C或C++运行时库(RTL)的情况下构建我的程序。我没有链接到DLL版本或静态版本。我甚至不包括头文件。我的这个很好用,c++,visual-c++,intrinsics,memset,demoscene,C++,Visual C++,Intrinsics,Memset,Demoscene,一些RTL函数,如memset(),可能很有用,所以我尝试添加自己的实现。它在调试构建中运行良好(即使对于编译器生成对memset()的隐式调用的地方也是如此)。但是在发布版本中,我得到一个错误,说我不能定义一个内在函数。您可以看到,在发布版本中,内部函数被启用,memset()是一个内部函数 我希望在我的发布版本中使用memset()的内在特性,因为它可能是内联的,比我的实现更小更快。但我似乎是第二十二条军规中的一员。如果我没有定义memset(),链接器会抱怨它未定义。如果我定义了它,编译器
memset()
,可能很有用,所以我尝试添加自己的实现。它在调试构建中运行良好(即使对于编译器生成对memset()
的隐式调用的地方也是如此)。但是在发布版本中,我得到一个错误,说我不能定义一个内在函数。您可以看到,在发布版本中,内部函数被启用,memset()
是一个内部函数
我希望在我的发布版本中使用memset()
的内在特性,因为它可能是内联的,比我的实现更小更快。但我似乎是第二十二条军规中的一员。如果我没有定义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;
}
如果使用memset()
的实现进行编译,则会出现编译器错误:
error C2169: 'memset' : intrinsic function, cannot be defined
如果我编译此文件时没有实现memset()
,则会出现链接器错误:
error LNK2001: unresolved external symbol _memset
Enable Intrinsic Functions: No
Whole Program Optimization: No
这是最后一个抑制“编译器助手”,如内置的memset
编辑以添加:
现在它已经解耦,您可以将asm代码从memset.asm复制到您的程序中——它有一个全局引用,但您可以删除它。它足够大,所以它不是内联的,但是如果你删除了它用来提高速度的所有技巧,你可能会使它足够小
我以上面的示例为例,将memset()
替换为:
void * __cdecl memset(void *pTarget, char value, size_t cbTarget) {
_asm {
push ecx
push edi
mov al, value
mov ecx, cbTarget
mov edi, pTarget
rep stosb
pop edi
pop ecx
}
return pTarget;
}
它可以工作,但库的版本要快得多。我认为您必须将优化设置为“最小化大小(/O1)”或“禁用(/Od)”,才能编译发行版配置;至少这就是VS2005带给我的诀窍。intrinsic是为速度而设计的,因此它们可以用于其他优化级别(速度和完整)。只需将函数命名为稍有不同的名称。我想我终于找到了一个解决方案: 首先,在头文件中,用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;
}
#pragma函数(memset)
void*\u cdecl memset(void*pTarget,int值,size\u t cbTarget){
无符号字符*p=静态_转换(pTarget);
而(cbTarget-->0){
*p++=静态_转换(值);
}
返回目标;
}
这为优化器决定不使用内部版本的情况提供了一个实现
突出的缺点是必须禁用整个程序优化(/GL和/LTCG)。我不知道为什么。如果有人找到了在不禁用全局优化的情况下执行此操作的方法,请插话。常规运行时库执行此操作的方法是编译具有memset定义的程序集文件并将其链接到运行时库中(您可以在C:\Program Files\Microsoft Visual Studio 10.0\VC\crt\src\intel\memset.asm中或其周围找到程序集文件)。即使对整个程序进行优化,这种方法也可以正常工作
还请注意,编译器仅在某些特殊情况下(当大小恒定且较小时?)使用memset内部函数。它通常使用您提供的memset函数,因此您可能应该使用memset.asm中的优化函数,除非您要编写同样优化的函数。这肯定适用于VS 2015:
添加命令行选项/Oi-。这是因为内在函数上的“否”不是开关,它是未指定的。/Oi-所有问题都会消失(它应该与整个程序优化一起工作,但我还没有正确地测试它).当您第一次问这个问题时,这当然不是一个答案,但是现在可以使用Visual Studio 2019提供的Clang版本来做您想做的事情,在那里,它的工作方式与您希望的一样,没有任何特殊的障碍 使用Clang还有其他一些好处——特别是如果您希望使用x64体系结构也实现类似的目标,因为这似乎是消除已损坏的pdata部分的唯一方法
#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;
}