【C語言經(jīng)典面試題】memcpy函數(shù)有沒有更高效的拷貝實現(xiàn)方法?
我相信大部分初中級C程序員在面試的過程中,可能都被問過關(guān)于memcpy函數(shù)的問題,甚至需要手撕memcpy。本文從另一個角度帶你領(lǐng)悟一下memcpy的面試題,你可以看看是否能接得???
1 寫在前面2 源碼實現(xiàn)2.1 函數(shù)申明2.2 簡單的功能實現(xiàn)2.3 滿足大數(shù)據(jù)量拷貝的功能實現(xiàn)3 源碼測試4 小小總結(jié)5 更多分享
1 寫在前面
假如你遇到下面的面試題,你會怎么做?題目大意如下:
請參考標準C庫對memcpy的申明定義,使用C語言的語法實現(xiàn)其基本功能,并盡量保證它在拷貝大數(shù)據(jù)(KK級別)的時候,有比較好的性能表現(xiàn)。
2 源碼實現(xiàn)
2.1 函數(shù)申明
通過查看man幫助,我們可以知道m(xù)emcpy函數(shù)的功能及其簡要申明。
NAME
memcpy - copy memory area
?
SYNOPSIS
#include
英文翻譯過來就是說,memcpy實現(xiàn)的就是內(nèi)存拷貝,其是按字節(jié)進行拷貝,同時還可能會存在內(nèi)存區(qū)域重合的情況。
2.2 簡單的功能實現(xiàn)
根據(jù)功能需求,以下是我的一個簡單實現(xiàn)源碼,僅供參考:
char *my_memcpy(char* dest, const char *src, size_t len)
{
assert(dest && src && (len > 0));
if (dest == src) {
;
} else {
char *p = dest;
size_t i;
for (i = 0; i < len; i++) {
*p++ = *src++;
}
}
?
return dest;
}
但是,這段代碼的缺陷也比較明顯,但數(shù)據(jù)量過大的時,即len很大時,整一個拷貝耗時將會非常不理想。那么如果考慮性能問題,又該如何實現(xiàn)它呢?
2.3 滿足大數(shù)據(jù)量拷貝的功能實現(xiàn)
下面給出一個參考實現(xiàn):
/* Nonzero if either X or Y is not aligned on a "long" boundary. */
#define UNALIGNED(X, Y) \\
(((long)X & (sizeof(long) - 1)) | ((long)Y & (sizeof(long) - 1)))
?
/* How many bytes are copied each iteration of the 4X unrolled loop. */
#define BIGBLOCKSIZE (sizeof(long) << 2)
?
/* How many bytes are copied each iteration of the word copy loop. */
#define LITTLEBLOCKSIZE (sizeof(long))
?
/* Threshhold for punting to the byte copier. */
#define TOO_SMALL(LEN) ((LEN) < BIGBLOCKSIZE)
?
char *my_memcopy_super(char* dest0, const char *src0, size_t len0)
{
assert(dest0 && src0 && (len0 > 0));
char *dest = dest0;
const char *src = src0;
long *aligned_dest;
const long *aligned_src;
?
/* If the size is small, or either SRC or DST is unaligned,
then punt into the byte copy loop. This should be rare. */
if (!TOO_SMALL(len0) && !UNALIGNED(src, dest)) {
aligned_dest = (long *)dest;
aligned_src = (long *)src;
?
/* Copy 4X long words at a time if possible. */
while (len0 >= BIGBLOCKSIZE) {
*aligned_dest++ = *aligned_src++;
*aligned_dest++ = *aligned_src++;
*aligned_dest++ = *aligned_src++;
*aligned_dest++ = *aligned_src++;
len0 -= BIGBLOCKSIZE;
}
?
/* Copy one long word at a time if possible. */
while (len0 >= LITTLEBLOCKSIZE) {
*aligned_dest++ = *aligned_src++;
len0 -= LITTLEBLOCKSIZE;
}
?
/* Pick up any residual with a byte copier. */
dest = (char *)aligned_dest;
src = (char *)aligned_src;
}
?
while (len0--)
*dest++ = *src++;
?
return dest0;
}
?
我們可以看到,里面做了對齊的判斷,還有數(shù)據(jù)量長度的判斷;通過充分利用機器的操作性能,從而提升memcpy拷貝的效率。
3 源碼測試
**簡單的測試代碼如下,目的就是測試在拷貝 **1KB數(shù)據(jù)和10MB數(shù)據(jù) 時,標準C的memcpy、自定義的memcpy_normal、以及自定義的memcpy_super直接的性能差異:
#include
#include
?
static void get_rand_bytes(unsigned char *data, int len)
{
int a;
int i;
?
srand((unsigned)time(NULL)); //種下隨機種子
for (i = 0; i < len; i++) {
data[i] = rand() % 255; //取隨機數(shù),并保證數(shù)在0-255之間
//printf("%02X ", data[i]);
}
}
?
static int get_cur_time_us(void)
{
struct timeval tv;
?
gettimeofday(&tv, NULL); //使用gettimeofday獲取當前系統(tǒng)時間
?
return (tv.tv_sec * 1000 * 1000 + tv.tv_usec); //利用struct timeval結(jié)構(gòu)體將時間轉(zhuǎn)換為ms
}
?
#define ARRAY_SIZE(n) sizeof(n) / sizeof(n[0])
?
int main(void)
{
int size_list[] = {
1024 * 1024 * 10, // 10MB
1024 * 1024 * 1, // 1MB
1024 * 100, // 100KB
1024 * 10, // 10KB
1024 * 1, // 1KB
};
char *data1;
char *data2;
int t1;
int t2;
int i = 0;
?
data1 = (char *)malloc(size_list[0]);
data2 = (char *)malloc(size_list[0]);
?
get_rand_bytes(data1, size_list[0]);
?
for (i = 0; i < ARRAY_SIZE(size_list); i++) {
t1 = get_cur_time_us();
memcpy(data2, data1, size_list[i]);
t2 = get_cur_time_us();
printf("copy %d bytes, memcpy_stdc waste time %dus\\n", size_list[i], t2 - t1);
?
t1 = get_cur_time_us();
my_memcopy_normal(data2, data1, size_list[i]);
t2 = get_cur_time_us();
printf("copy %d bytes, memcpy_normal waste time %dus\\n", size_list[i], t2 - t1);
?
t1 = get_cur_time_us();
my_memcopy_super(data2, data1, size_list[i]);
t2 = get_cur_time_us();
printf("copy %d bytes, memcpy_super waste time %dus\\n\\n", size_list[i], t2 - t1);
}
?
free(data1);
free(data2);
?
return 0;
}
?
簡單執(zhí)行編譯后,運行小程序的結(jié)果:
從運行結(jié)果上看:
- **拷貝數(shù)據(jù)量比較小時,拷貝效率排行: **normal < super < stdc
- **拷貝數(shù)據(jù)量比較大時,拷貝效率排行: **normal < stdc < super
4 小小總結(jié)
memcpy的源碼實現(xiàn),核心就是內(nèi)存拷貝,要想提升拷貝的效率,還得充分利用機器的運算性能,比如考慮對齊問題。
綜合來看,標準C庫實現(xiàn)的memcpy在大部分的場景下都可以有一個比較好的性能表現(xiàn),這一點是值得稱贊的。
5 更多分享
[架構(gòu)師李肯]
架構(gòu)師李肯 ( 全網(wǎng)同名 ),一個專注于嵌入式IoT領(lǐng)域的架構(gòu)師。有著近10年的嵌入式一線開發(fā)經(jīng)驗,深耕IoT領(lǐng)域多年,熟知IoT領(lǐng)域的業(yè)務(wù)發(fā)展,深度掌握IoT領(lǐng)域的相關(guān)技術(shù)棧,包括但不限于主流RTOS內(nèi)核的實現(xiàn)及其移植、硬件驅(qū)動移植開發(fā)、網(wǎng)絡(luò)通訊協(xié)議開發(fā)、編譯構(gòu)建原理及其實現(xiàn)、底層匯編及編譯原理、編譯優(yōu)化及代碼重構(gòu)、主流IoT云平臺的對接、嵌入式IoT系統(tǒng)的架構(gòu)設(shè)計等等。擁有多項IoT領(lǐng)域的發(fā)明專利,熱衷于技術(shù)分享,有多年撰寫技術(shù)博客的經(jīng)驗積累,連續(xù)多月獲得RT-Thread官方技術(shù)社區(qū)原創(chuàng)技術(shù)博文優(yōu)秀獎,榮獲[CSDN博客專家]、[CSDN物聯(lián)網(wǎng)領(lǐng)域優(yōu)質(zhì)創(chuàng)作者]、[2021年度CSDN&RT-Thread技術(shù)社區(qū)之星]、[2022年RT-Thread全球技術(shù)大會講師]、[RT-Thread官方嵌入式開源社區(qū)認證專家]、[RT-Thread 2021年度論壇之星TOP4]、[華為云云享專家(嵌入式物聯(lián)網(wǎng)架構(gòu)設(shè)計師)]等榮譽。堅信【知識改變命運,技術(shù)改變世界】!
審核編輯:湯梓紅
-
函數(shù)
+關(guān)注
關(guān)注
3文章
4345瀏覽量
62867 -
RT-Thread
+關(guān)注
關(guān)注
31文章
1305瀏覽量
40307 -
memcpy
+關(guān)注
關(guān)注
0文章
9瀏覽量
2835
發(fā)布評論請先 登錄
相關(guān)推薦
評論