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