如何在没有运行时库的情况下使用 VC++ 内在函数

2021-12-22 00:00:00 visual-c++ c++ intrinsics memset demoscene

我参与了其中一项挑战,即您尝试生成尽可能小的二进制文件,因此我正在构建我的程序, 没有 C 或 C++ 运行时库 (RTL).我没有链接到 DLL 版本或静态版本.我什至没有 #include 头文件.我有这个工作正常.

I'm involved in one of those challenges where you try to produce the smallest possible binary, so I'm building my program without the C or C++ run-time libraries (RTL). I don't link to the DLL version or the static version. I don't even #include the header files. I have this working fine.

某些 RTL 函数,例如 memset(),可能很有用,因此我尝试添加自己的实现.它在调试版本中运行良好(即使在编译器生成对 memset() 的隐式调用的那些地方).但是在 Release 版本中,我收到一条错误消息,指出我无法定义内在函数.您会看到,在 Release 版本中,启用了内部函数,并且 memset() 是一个内部函数.

Some RTL functions, like memset(), can be useful, so I tried adding my own implementation. It works fine in Debug builds (even for those places where the compiler generates an implicit call to memset()). But in Release builds, I get an error saying that I cannot define an intrinsic function. You see, in Release builds, intrinsic functions are enabled, and memset() is an intrinsic.

我希望在我的发布版本中使用 memset() 的内在函数,因为它可能是内联的,并且比我的实现更小、更快.但我似乎是第 22 名.如果我没有定义 memset(),链接器会抱怨它是未定义的.如果我确实定义了它,编译器会抱怨我无法定义内在函数.

I would love to use the intrinsic for memset() in my release builds, since it's probably inlined and smaller and faster than my implementation. But I seem to be a in catch-22. If I don't define memset(), the linker complains that it's undefined. If I do define it, the compiler complains that I cannot define an intrinsic function.

有谁知道定义、声明、#pragma 以及编译器和链接器标志的正确组合,以在不引入 RTL 开销的情况下获得内在函数?

Does anyone know the right combination of definition, declaration, #pragma, and compiler and linker flags to get an intrinsic function without pulling in RTL overhead?

Visual Studio 2008、x86、Windows XP+.

Visual Studio 2008, x86, Windows XP+.

为了让问题更具体一点:

To make the problem a little more concrete:

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() 的实现进行编译,我会收到一个编译器错误:

If I compile with my implementation of memset(), I get a compiler error:

error C2169: 'memset' : intrinsic function, cannot be defined

如果我在没有实现 memset() 的情况下编译它,我会收到一个链接器错误:

If I compile this without my implementation of memset(), I get a linker error:

error LNK2001: unresolved external symbol _memset

推荐答案

我想我终于找到了解决方案:

I think I finally found a solution:

首先,在头文件中,使用编译指示声明 memset(),如下所示:

First, in a header file, declare memset() with a pragma, like so:

extern "C" void * __cdecl memset(void *, int, size_t);
#pragma intrinsic(memset)

这允许您的代码调用 memset().在大多数情况下,编译器会内联内部版本.

That allows your code to call memset(). In most cases, the compiler will inline the intrinsic version.

其次,在单独的实现文件中,提供一个实现.防止编译器抱怨重新定义一个内在函数的技巧是首先使用另一个 pragma.像这样:

Second, in a separate implementation file, provide an implementation. The trick to preventing the compiler from complaining about re-defining an intrinsic function is to use another pragma first. Like this:

#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;
}

这为优化器决定不使用内部版本的情况提供了一种实现.

This provides an implementation for those cases where the optimizer decides not to use the intrinsic version.

突出的缺点是您必须禁用整个程序优化(/GL 和/LTCG).我不知道为什么.如果有人找到了一种无需禁用全局优化的方法,请加入.

The outstanding drawback is that you have to disable whole-program optimization (/GL and /LTCG). I'm not sure why. If someone finds a way to do this without disabling global optimization, please chime in.

相关文章