Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用VC++;不带运行时库的内部函数 我参与了其中的一个挑战,在这里你尝试生成最小可能的二进制,所以我在没有C或C++运行时库(RTL)的情况下构建我的程序。我没有链接到DLL版本或静态版本。我甚至不包括头文件。我的这个很好用_C++_Visual C++_Intrinsics_Memset_Demoscene - Fatal编程技术网

如何使用VC++;不带运行时库的内部函数 我参与了其中的一个挑战,在这里你尝试生成最小可能的二进制,所以我在没有C或C++运行时库(RTL)的情况下构建我的程序。我没有链接到DLL版本或静态版本。我甚至不包括头文件。我的这个很好用

如何使用VC++;不带运行时库的内部函数 我参与了其中的一个挑战,在这里你尝试生成最小可能的二进制,所以我在没有C或C++运行时库(RTL)的情况下构建我的程序。我没有链接到DLL版本或静态版本。我甚至不包括头文件。我的这个很好用,c++,visual-c++,intrinsics,memset,demoscene,C++,Visual C++,Intrinsics,Memset,Demoscene,一些RTL函数,如memset(),可能很有用,所以我尝试添加自己的实现。它在调试构建中运行良好(即使对于编译器生成对memset()的隐式调用的地方也是如此)。但是在发布版本中,我得到一个错误,说我不能定义一个内在函数。您可以看到,在发布版本中,内部函数被启用,memset()是一个内部函数 我希望在我的发布版本中使用memset()的内在特性,因为它可能是内联的,比我的实现更小更快。但我似乎是第二十二条军规中的一员。如果我没有定义memset(),链接器会抱怨它未定义。如果我定义了它,编译器

一些RTL函数,如
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
  • 我很确定有一个编译器标志告诉VC++不要使用内部函数

  • 运行库的源代码随编译器一起安装。您可以选择您想要/需要的摘录函数,但通常您必须对它们进行大量修改(因为它们包含您不想要/不需要的特性和/或依赖项)

  • 还有其他可用的开源运行库,它们可能需要更少的定制

  • 如果你真的对此很认真,你需要知道(也许还需要使用)汇编语言

  • 编辑以添加:

    我有你的新测试代码要编译和链接。以下是相关设置:

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