【C語(yǔ)言經(jīng)典面試題】memcpy函數(shù)有沒有更高效的拷貝實(shí)現(xiàn)方法?
我相信大部分初中級(jí)C程序員在面試的過(guò)程中,可能都被問(wèn)過(guò)關(guān)于memcpy函數(shù)的問(wèn)題,甚至需要手撕memcpy。本文從另一個(gè)角度帶你領(lǐng)悟一下memcpy的面試題,你可以看看是否能接得???
1 寫在前面2 源碼實(shí)現(xiàn)2.1 函數(shù)申明2.2 簡(jiǎn)單的功能實(shí)現(xiàn)2.3 滿足大數(shù)據(jù)量拷貝的功能實(shí)現(xiàn)3 源碼測(cè)試4 小小總結(jié)5 更多分享
1 寫在前面
假如你遇到下面的面試題,你會(huì)怎么做?題目大意如下:
請(qǐng)參考標(biāo)準(zhǔn)C庫(kù)對(duì)memcpy的申明定義,使用C語(yǔ)言的語(yǔ)法實(shí)現(xiàn)其基本功能,并盡量保證它在拷貝大數(shù)據(jù)(KK級(jí)別)的時(shí)候,有比較好的性能表現(xiàn)。
2 源碼實(shí)現(xiàn)
2.1 函數(shù)申明
通過(guò)查看man幫助,我們可以知道m(xù)emcpy函數(shù)的功能及其簡(jiǎn)要申明。
NAME
memcpy - copy memory area
?
SYNOPSIS
#include
英文翻譯過(guò)來(lái)就是說(shuō),memcpy實(shí)現(xiàn)的就是內(nèi)存拷貝,其是按字節(jié)進(jìn)行拷貝,同時(shí)還可能會(huì)存在內(nèi)存區(qū)域重合的情況。
2.2 簡(jiǎn)單的功能實(shí)現(xiàn)
根據(jù)功能需求,以下是我的一個(gè)簡(jiǎn)單實(shí)現(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ù)量過(guò)大的時(shí),即len很大時(shí),整一個(gè)拷貝耗時(shí)將會(huì)非常不理想。那么如果考慮性能問(wèn)題,又該如何實(shí)現(xiàn)它呢?
2.3 滿足大數(shù)據(jù)量拷貝的功能實(shí)現(xiàn)
下面給出一個(gè)參考實(shí)現(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;
}
?
我們可以看到,里面做了對(duì)齊的判斷,還有數(shù)據(jù)量長(zhǎng)度的判斷;通過(guò)充分利用機(jī)器的操作性能,從而提升memcpy拷貝的效率。
3 源碼測(cè)試
**簡(jiǎn)單的測(cè)試代碼如下,目的就是測(cè)試在拷貝 **1KB數(shù)據(jù)和10MB數(shù)據(jù) 時(shí),標(biāo)準(zhǔn)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)); //種下隨機(jī)種子
for (i = 0; i < len; i++) {
data[i] = rand() % 255; //取隨機(jī)數(shù),并保證數(shù)在0-255之間
//printf("%02X ", data[i]);
}
}
?
static int get_cur_time_us(void)
{
struct timeval tv;
?
gettimeofday(&tv, NULL); //使用gettimeofday獲取當(dāng)前系統(tǒng)時(shí)間
?
return (tv.tv_sec * 1000 * 1000 + tv.tv_usec); //利用struct timeval結(jié)構(gòu)體將時(shí)間轉(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;
}
?
簡(jiǎn)單執(zhí)行編譯后,運(yùn)行小程序的結(jié)果:
從運(yùn)行結(jié)果上看:
- **拷貝數(shù)據(jù)量比較小時(shí),拷貝效率排行: **normal < super < stdc
- **拷貝數(shù)據(jù)量比較大時(shí),拷貝效率排行: **normal < stdc < super
4 小小總結(jié)
memcpy的源碼實(shí)現(xiàn),核心就是內(nèi)存拷貝,要想提升拷貝的效率,還得充分利用機(jī)器的運(yùn)算性能,比如考慮對(duì)齊問(wèn)題。
綜合來(lái)看,標(biāo)準(zhǔn)C庫(kù)實(shí)現(xiàn)的memcpy在大部分的場(chǎng)景下都可以有一個(gè)比較好的性能表現(xiàn),這一點(diǎn)是值得稱贊的。
5 更多分享
[架構(gòu)師李肯]
架構(gòu)師李肯 ( 全網(wǎng)同名 ),一個(gè)專注于嵌入式IoT領(lǐng)域的架構(gòu)師。有著近10年的嵌入式一線開發(fā)經(jīng)驗(yàn),深耕IoT領(lǐng)域多年,熟知IoT領(lǐng)域的業(yè)務(wù)發(fā)展,深度掌握IoT領(lǐng)域的相關(guān)技術(shù)棧,包括但不限于主流RTOS內(nèi)核的實(shí)現(xiàn)及其移植、硬件驅(qū)動(dòng)移植開發(fā)、網(wǎng)絡(luò)通訊協(xié)議開發(fā)、編譯構(gòu)建原理及其實(shí)現(xiàn)、底層匯編及編譯原理、編譯優(yōu)化及代碼重構(gòu)、主流IoT云平臺(tái)的對(duì)接、嵌入式IoT系統(tǒng)的架構(gòu)設(shè)計(jì)等等。擁有多項(xiàng)IoT領(lǐng)域的發(fā)明專利,熱衷于技術(shù)分享,有多年撰寫技術(shù)博客的經(jīng)驗(yàn)積累,連續(xù)多月獲得RT-Thread官方技術(shù)社區(qū)原創(chuàng)技術(shù)博文優(yōu)秀獎(jiǎng),榮獲[CSDN博客專家]、[CSDN物聯(lián)網(wǎng)領(lǐng)域優(yōu)質(zhì)創(chuàng)作者]、[2021年度CSDN&RT-Thread技術(shù)社區(qū)之星]、[2022年RT-Thread全球技術(shù)大會(huì)講師]、[RT-Thread官方嵌入式開源社區(qū)認(rèn)證專家]、[RT-Thread 2021年度論壇之星TOP4]、[華為云云享專家(嵌入式物聯(lián)網(wǎng)架構(gòu)設(shè)計(jì)師)]等榮譽(yù)。堅(jiān)信【知識(shí)改變命運(yùn),技術(shù)改變世界】!
審核編輯:湯梓紅
-
函數(shù)
+關(guān)注
關(guān)注
3文章
4381瀏覽量
64898 -
RT-Thread
+關(guān)注
關(guān)注
32文章
1409瀏覽量
41962 -
memcpy
+關(guān)注
關(guān)注
0文章
9瀏覽量
2930
發(fā)布評(píng)論請(qǐng)先 登錄
【C語(yǔ)言經(jīng)典面試題】源碼實(shí)現(xiàn)標(biāo)準(zhǔn)庫(kù)函數(shù)memcpy
高效率的內(nèi)存拷貝函數(shù)memcpy
HBase性能優(yōu)化方法總結(jié)
MSP430FRx MCU如何實(shí)現(xiàn)更高性能
memCopy函數(shù)怎么實(shí)現(xiàn)拷貝的呢?
STM32中的memcpy函數(shù)的使用 精選資料推薦
memcpy怎么用_memcpy用法總結(jié)

淺談linux c編程中的拷貝函數(shù)
C++:詳談拷貝構(gòu)造函數(shù)

C語(yǔ)言模擬實(shí)現(xiàn)memcpy函數(shù)

C語(yǔ)言模擬實(shí)現(xiàn)memmove函數(shù)

memcpy函數(shù)實(shí)現(xiàn)及其優(yōu)化
C++之拷貝構(gòu)造函數(shù)的淺copy及深copy
C語(yǔ)言庫(kù)memcpy和memmove的區(qū)別分析
memcpy和memmove的區(qū)別是什么

評(píng)論