簡體   English   中英

復制 C 中的 mem 塊時防止 memory 混疊

[英]Preventing memory aliasing when copying mem blocks in C

我想我生銹了,所以請和我一起裸露。 我會盡量簡短。

Q1。 當試圖復制緩沖區時,比如buf2buf1 ,以下檢查是否足以防止混疊?

if (buf2 >= buf1 && buf2 < buf1 + buf1size) {
    // aliasing
}

Q2。 如果是這樣,我們是否可以根據情況選擇性地使用memcopy()memmove() ,像這樣?

// use memcpy() by default
void *(*funcp)(void *restrict, const void *restrict, size_t) = &memcpy;

// switch to memmove() when aliasing
if ( aliasing ) {
    // this cast FORCEFULLY changes the type-qualifiers of the declared parameters
    funcp = (void *(*)(void *, const void *, size_t)) &memmove;
}

// later on ...
if ( buf2size <= buf1size ) {
    (*funcp)( buf1, buf2, buf2size ); // funcp() works too, I prefer making it explicit
}

它可以工作,但是當切換到memmove()時,我對強制轉換參數的類型限定符一點也不滿意 我認為標准證實了我的懷疑(當我需要它們時永遠找不到這些該死的東西......使用C99順便說一句),但由於代碼有效,我想更加確定,因為如果它可以這樣它會拯救我從復制buf2開始,使用副本並在完成后釋放它。

我相信術語“內存區域重疊”使用得更頻繁。

沒有可移植的方式來進行這種指針比較。 標准庫實現必須比較指針,但在這種情況下,庫的作者確切地知道這種比較是如何工作的。

最流行的 glibc 實現使用unsigned long longunsigned long整數來比較指針(或者更確切地說執行地址算法)。

Q2。 如果是這樣,我們是否可以根據情況有選擇地使用 memcopy() 或 memmove() ,像這樣

這是沒有意義的,因為 remove 會檢查它本身。 Most implementations I know do not follow the C standard way of moving memory areas - ie do not create any temporary arrays only decide in which direction to copy the memory areas. 如果 memory 區域不重疊,則復制操作與使用memcpy時的速度相同。

最流行的實現(gnu C 庫 glibc):

rettype
inhibit_loop_to_libcall
MEMMOVE (a1const void *a1, a2const void *a2, size_t len)
{
  unsigned long int dstp = (long int) dest;
  unsigned long int srcp = (long int) src;

  /* This test makes the forward copying code be used whenever possible.
     Reduces the working set.  */
  if (dstp - srcp >= len)   /* *Unsigned* compare!  */
    {
      /* Copy from the beginning to the end.  */

#if MEMCPY_OK_FOR_FWD_MEMMOVE
      dest = memcpy (dest, src, len);
#else
      /* If there not too few bytes to copy, use word copy.  */
      if (len >= OP_T_THRES)
    {
      /* Copy just a few bytes to make DSTP aligned.  */
      len -= (-dstp) % OPSIZ;
      BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ);

      /* Copy whole pages from SRCP to DSTP by virtual address
         manipulation, as much as possible.  */

      PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len);

      /* Copy from SRCP to DSTP taking advantage of the known
         alignment of DSTP.  Number of bytes remaining is put
         in the third argument, i.e. in LEN.  This number may
         vary from machine to machine.  */

      WORD_COPY_FWD (dstp, srcp, len, len);

      /* Fall out and copy the tail.  */
    }

      /* There are just a few bytes to copy.  Use byte memory operations.  */
      BYTE_COPY_FWD (dstp, srcp, len);
#endif /* MEMCPY_OK_FOR_FWD_MEMMOVE */
    }
  else
    {
      /* Copy from the end to the beginning.  */
      srcp += len;
      dstp += len;

      /* If there not too few bytes to copy, use word copy.  */
      if (len >= OP_T_THRES)
    {
      /* Copy just a few bytes to make DSTP aligned.  */
      len -= dstp % OPSIZ;
      BYTE_COPY_BWD (dstp, srcp, dstp % OPSIZ);

      /* Copy from SRCP to DSTP taking advantage of the known
         alignment of DSTP.  Number of bytes remaining is put
         in the third argument, i.e. in LEN.  This number may
         vary from machine to machine.  */

      WORD_COPY_BWD (dstp, srcp, len, len);

      /* Fall out and copy the tail.  */
    }

      /* There are just a few bytes to copy.  Use byte memory operations.  */
      BYTE_COPY_BWD (dstp, srcp, len);
    }

  RETURN (dest);
}

對於任何兩個通用指針,您都不能真正對它們進行指針運算。 這是由加法運算符 C17 6.5.6/8 規定的:

如果指針操作數和結果都指向同一個數組 object 的元素,或數組 object 的最后一個元素,則評估不應產生溢出; 否則,行為未定義。

關系運算符 (6.5.8) 存在類似的文本 - 與它們進行比較的任何兩個指針必須指向同一個數組,否則行為未定義。

理論上,您可以將指針轉換為uintptr_t形式的整數並對其進行算術運算。 如果您確定buf1指向buf1size項數組的開頭,那么理論上您可以通過對uintptr_t執行 integer 算術來計算buf2是否指向同一數組。 但這並沒有什么好處。

相反,您可以簡單地將 function 寫為

void func (char* restrict buf1, char* restrict buf2);

並將確保兩個緩沖區不別名的責任推給調用者。

至於你的 function 指針選擇memcpymemmove ,那么顯然主流編譯器(gcc,clang)似乎忽略了一個版本restrict合格的指針。 如果這是否符合行為,我不確定。

暫無
暫無

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

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