某日二師兄參加XXX科技公司的C++工程師開發崗位第31面:
面試官:
strcpy
函數使用過吧?二師兄:用過。
面試官:這個函數有什麼作用?
二師兄:主要用做字串複製,將於字元從一個位置複製到另一個位置。
面試官:
strncpy
函數也使用過吧,和strcpy
有何不同?二師兄:
strncpy
多了一個size_t
的引數,用於避免緩衝區溢位。面試官:能否實現一個
strncpy
函數?二師兄:好的。
void strncpy(char *dest, char *src, size_t n)
{
for (size_t i = 0; i < n; i++)
{
*(dest + i) = *(src + i);
}
}
面試官:額。。如果
strlen(src) < n
會發生什麼?二師兄:嗯。。那要做個判斷。。
void strncpy(char *dest, char *src, size_t n)
{
size_t len = strlen(src) > n ? n : strlen(src);
for (size_t i = 0; i < len; i++)
{
*(dest + i) = *(src + i);
}
}
面試官:如果
strlen(dest) < n
呢?二師兄:因為
n
是程式設計師傳入進來的,且無法知曉dest的長度,所以這個n
要程式設計師保證它的正確性。面試官:有沒有更簡潔的寫法?比如利用指標的自增?
二師兄:讓我想想。。
void strncpy(char *dest, char *src, size_t n)
{
while(n-- && (*dest++ = *src++));
}
面試官:如果使用者傳入的
src
是字串常數,會發生什麼?二師兄:額。。。讓我想想。。明白了,要在
src
前加上const
修飾符:
void strncpy(char *dest, const char *src, size_t n)
{
while(n-- && (*dest++ = *src++));
}
面試官:有一些操作需要
strcpy
巢狀strcpy
,如果要實現這個功能,需要做哪些修改?二師兄:你說的是
strncpy(strncpy(...)...)
這種操作嗎?面試官:是的。
二師兄:那麼需要返回
dest
地址:
char *strncpy(char *dest, const char *src, size_t n)
{
char *ret = dest;
while (n-- && (*dest++ = *src++));
return ret;
}
面試官:如果
src
和dest
的記憶體地址有重疊,會發生什麼?二師兄:這要分為兩種情況,第一種情況:
dest < src < dest+n
:
二師兄:此時並不需要特殊的處理,拷貝完成後,整個字串是這樣的:
二師兄:雖然
src
被覆寫了,但是dest
的內容是正確的。二師兄:第二種情況,
src < dest <src+n
;
二師兄:如果直接拷貝,結果會變成這樣:
二師兄:此時
dest
的內容是錯誤的。所以我們需要對這種情況做特殊處理:
char *strncpy(char *dest, const char *src, size_t n)
{
char *ret = dest;
size_t len = strlen(src) > n ? n :strlen(src);
if(src < dest && dest < src + len) //需要從尾部開始拷貝
{
const char* s = src + len - 1;
char* d = dest + len - 1;
while(len --) *d-- = *s--;
return ret;
}
while (n-- && (*dest++ = *src++));
return ret;
}
面試官:嗯。有沒有什麼辦法對以上的程式碼做一些效能上的優化?
二師兄:可以使用
SIMD(Single Instruction Multiple Data)
指令對strncpy
函數做一些優化。*dest++ = *src++
每次只能複製一個位元組的內容,而SIMD
每次可以複製超過一個位元組的內容,當資料量大的時候,效率會有明顯的提升。面試官:寫過
SIMD
相關的程式碼嗎?二師兄:只是聽說過,沒有用過。
面試官:好的,今天就到這裡,請回去等通知吧。
什麼是SIMD
?SIMD
真的能夠提升效率嗎?
SIMD
是一種常見的平行計算技術,一條指令可以同時處理多個資料,所以它可以減少指令的數量,從而提高處理速度。
在X86_64
架構下,SIMD
的指令集主要包括MMX
、SSE
、AVX
。
下面程式碼演示如果使用SIMD
技術加速大容量字串的拷貝:
#include <emmintrin.h>
void strncpy_simd(char *dest, const char *src, size_t n)
{
size_t len = strlen(src) > n ? n : strlen(src);
__m128i *d = (__m128i *)dest;
const __m128i *s = (const __m128i *)src;
while (len >= sizeof(__m128i))
{
_mm_storeu_si128(d++, _mm_loadu_si128(s++));
len -= sizeof(__m128i);
}
char *dc = (char *)d;
const char *sc = (const char *)s;
while (len--)
{
*dc++ = *sc++;
}
}
今天的面試到這裡就結束了,感謝大家的耐心~
關注我,帶你21天「精通」C++!(狗頭)