簡體   English   中英

以安全的方式更換memcpy

[英]Replacing memcpy in a safe way

我想用我自己的優化版本替換memcpy來做一些基准測試。 我不想修改調用memcpy的代碼中的每個位置(這是一個很大的代碼庫,我想避免很多更改)。 所以我做了以下事情:

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

上面的方法可以用我自己的實現替換memcpy,但是它看起來很粗糙,被迫而且並不安全。 還有其他選擇,以便我可以替換庫memcpy而不修改其余代碼嗎? 我應該忘記上面的內容,因為這樣做似乎不是明智的選擇,而只需修改所有其他文件(以及為什么)?

一些編譯器可以通過命令行包含頭文件。 例如,可以使用-include選項調用g++gcc

但是,我確定您的代碼至少可以在沒有自定義標頭的情況下進行編譯和運行,因為在沒有“神秘”編譯器標志的情況下,代碼被認為是“不好的舉止”而失敗。

另外:memcpy的標准庫實現通常已經 SSE2優化等優化。 您可能將無法做得更好。

我將假設您正在運行linux ...

附件鏈接是有關如何使用LD_PRELOAD替換應用程序中現有功能的示例。 該示例進行了正常的malloc調用,然后確保內存已清零。 如何將其轉換為memcpy應該很明顯。

https://gist.github.com/701897

如果您使用的是Linux,則memcpy已經非常優化,甚至可能做得太多(我認為我們發現memcpy一次在頁面邊框上崩潰了)。

就是說,您完全可以在程序中定義替換memcpy 它將代替C庫被調用。 除此之外,您無需執行其他任何操作。

我剛剛找到了另一種替換memcpy函數調用的方法。 它僅適用於GCC(我仍然需要找到另一種VC ++方法),但我認為它絕對比粗略的#define方法更好。 它使用__REDIRECT宏(通過features.h包含在sys/cdefs.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;
}

如果您不想更改現有代碼,那么這似乎是唯一可用的解決方案。 並不會太糟,因為如果您自己的memcpy的簽名與默認簽名不匹配,則編譯器會抱怨。

也就是說,我非常懷疑您是否會設法獲得比標准庫隨附的memcpy更好的性能。 但是,您是否要復制那么多的內存,而這根本就成了問題?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM