以安全的方式替换memcpy

时间:2011-09-04 19:20:46

标签: c++ c optimization

我想用自己的优化版本替换memcpy来做一些基准测试。 我不想修改调用memcpy的代码中的每个地方(这是一个很大的代码库,我想避免很多更改)。所以我做的是以下内容:

// in a "common" header file which is included everywhere
#ifdef SHOULD_OPTIMIZE
    #define memcpy my_on_steroids_memcpy
#endif

以上工作并将memcpy替换为我自己的实现,但它看起来很粗糙,强制而且根本不安全。是否有任何其他选择,以便我可以替换库memcpy而不修改其余的代码?我是否应该忘记上述内容,因为它似乎不是一个值得建议的事情,只是修改所有其他文件(以及为什么)?

5 个答案:

答案 0 :(得分:2)

某些编译器可以从命令行中包含标头。例如,可以使用g++选项调用gcc-include

但是,我确定你的代码至少在没有自定义标头的情况下进行编译和运行,因为如果没有“神秘”编译器标志,你的代码会被认为是“不礼貌”。

另外:memcpy的标准库实现通常已经 优化了SSE2优化等。你可能无法做得更好。

答案 1 :(得分:1)

我将假设您正在运行Linux ...

附加链接是关于如何使用LD_PRELOAD替换应用程序中现有函数的示例。该示例采用普通的malloc调用,然后确保内存已被清零。如何将其翻译成memcpy应该是相当明显的。

https://gist.github.com/701897

答案 2 :(得分:1)

如果您使用的是Linux,那么memcpy已经非常优化,可能甚至更多(我认为我们注意到在页面边框上使用memcpy会发生一次崩溃)。

也就是说,您完全可以在程序中定义替换memcpy。它将被调用而不是C库。你不必做任何其他事情。

答案 3 :(得分:1)

我刚刚找到了另一种替换memcpy函数调用的方法。它只适用于GCC(我仍然需要为VC ++找到另一种方法),但我认为它肯定比原始#define方式更好。它使用__REDIRECT宏(在sys/cdefs.h中包含的features.h),这是我在glibc中广泛使用的内容。下面是一个小测试的例子:

// modified.h
#pragma once

#ifndef MODIF_H_INCLUDED_
#define MODIF_H_INCLUDED_

#include <cstddef>
#include <features.h>

extern "C"
{
void test_memcpy(void* __restrict to, const void* __restrict from, size_t size);
}

#if defined(__GNUC__)
void __REDIRECT(memcpy, (void* __restrict to, const void* __restrict from, size_t size),
                test_memcpy);
#endif /* __GNUC__ */

#endif /* MODIF_H_INCLUDED_ */

//modified.cpp
extern "C" void test_memcpy(void* __restrict to, const void* __restrict from, 
                            size_t size)
{
    std::cout << "Dumb memcpy replacement!\n";
}

//original.h
#pragma once

#ifndef ORIG_H_INCLUDED_
#define ORIG_H_INCLUDED_

void test_with_orig();

#endif /* ORIG_H_INCLUDED_ */

//original.cpp
#include <cstring>
#include <iostream>

void test_with_orig()
{
    int* testDest = new int[10];
    int* testSrc = new int[10];

    for (unsigned int i = 0; i < 10; ++i)
    {
            testSrc[i] = i;
    }

    memcpy(testDest, testSrc, 10 * sizeof(int));

    for (unsigned int i = 0; i < 10; ++i)
    {
            std::cout << std::hex << "\nAfter standard memcpy - " 
            << "Source: " << testSrc[i] << "\tDest: " << testDest[i] << "\n";
    }
}

// and a small test
#include "modified.h"
#include "original.h"

#include <iostream>
#include <cstring>

int main()
{
    int* testDest = new int[10];
    int* testSrc = new int[10];

    for (unsigned int i = 0; i < 10; ++i)
    {
            testSrc[i] = i;
            testDest[i] = 0xDEADBEEF;
    }

    memcpy(testDest, testSrc, 10 * sizeof(int));

    for (unsigned int i = 0; i < 10; ++i)
    {
            std::cout << std::hex << "\nAfter memcpy replacement - " 
            << "Source: " << testSrc[i] << "\tDest: " << testDest[i] << "\n";
    }

    test_with_orig();

    return 0;
}

答案 4 :(得分:0)

如果您不想更改现有代码,这似乎是唯一可用的解决方案;并且它不应该太糟糕,因为如果您自己的memcpy的签名与默认签名不匹配,编译器会抱怨。

那就是说,我会怀疑你是否能够比标准库附带的memcpy挤出更好的性能。但是,你是否正在复制那些成为问题的记忆?