簡體   English   中英

動態 memory 分配期間的 Memory 地址截斷問題

[英]Memory address truncation issue during dynamic memory allocation

我有一個 fortran 子例程 (getmem.F),它使用 C 程序 (memalloc.c) 進行動態 memory 分配。 以下子例程和函數是用於研究目的的非常古老的大型代碼的一部分。 我在 64 位機器上編譯,我使用的是 PGI 編譯器 2020.4 版本。 以下是fortran代碼。

      subroutine getmem(ptr, size)

c-----get pointered memory

cdir$ nolist
      include 'common.h'
      include 'inputcom.h'
cdir$ list

      integer memalloc, memfree
      integer ptr, size, ierr0

c-----allocate 'size' words of memory and send back pointer in 'ptr'

      print *, "Value of ptr and size before memory allocation"
      print *, "ptr:", ptr               ! The value of ptr is 0
      print *, "size:", size             ! The value of size is 1138280

      if (size .lt. 0) then
        ierr0 = memfree (ptr)
      else
        ierr0 = memalloc (ptr, size)
      endif

      print *, "Value of ptr and size after memory allocation"
      print *, "ptr:", ptr               ! The value of ptr is -1431465968 (This is incorrect 
                                         ! value which is the decimal from signed 2's complement for 2863501328)
      print *, "size:", size             ! The value of size is 1138280

      if (ierr0 .ne. 0) then
        call writemsg ('Unable to get memory.')
        write (buffer, 100) size
  100   format ('GETMEM:  size is ', i15, '.')
        call writemsg (buffer)
        stop 'getmem'
      endif

      return
      end

這里是 C 代碼 memalloc.c

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h> /* Added by Surya */

int memalloc_ (int *nextptr, int *size)

{
  void *ptr;

  printf("Address of nextptr:%p \nValue of nextptr: %d \n", nextptr, *nextptr);
  /*Output: Address of nextptr: 0x1687ad0 
            Value of nextptr: 0 */

  /* Before Memory Allocation */

  printf("Address pointed by ptr (Value stored in ptr): %p \n", (void*)ptr);
  /*Output: Address pointed by ptr (Value stored in ptr): 0x7fffffff8b40 */   
         
  if (*nextptr == NULL) {
    if ((ptr = (void *) malloc (*size)) == NULL) {
      return(-1);
    }
  }
  else {
    if ((ptr = (void *) realloc (*nextptr, *size)) == NULL) {
      return(-1);
    }
  }
  /* After memory allocation using malloc() */

  printf("Address pointed by ptr (Value stored in ptr): %p \nValue when printed as a long integer %ld \n", (void*)ptr, (int*)ptr);
  /* Output: Address pointed by ptr (Value stored in ptr): 0x2aaaaaad9010
             Value when printed as a long integer: 46912496308240 */

  *nextptr = (int) ptr;

  printf("Address of nextptr:%p \nValue of nextptr: %d \n", nextptr, *nextptr);
  /* Output: Address of nextptr: 0x1687ad0
             Value of nextptr: -1431465968  */

  printf("Value of nextptr in long format: %ld \n", *nextptr);
  /* Output: Value of nextptr in long format: 2863501328  */

  return (0);
}

當我進行十六進制到十進制轉換(反之亦然)時( https://www.rapidtables.com/convert/number/hex-to-decimal.html ),我注意到了問題所在。 當我們做 (int) ptr. ptr = 0x2aaaaaad9010(十進制值為46912496308240)的十六進制值被截斷為aaad9010(十進制值為2863501328)。 當它作為 ptr 傳遞回 fortran77 代碼時,稍后用作指向 memory 的指針的 ptr 無法找到變量及其值。 如何解決此問題,以便 C 程序中不會發生截斷?

PS 這是一種非常古老的編碼風格,但它是我研究的一個更大的代碼(通過實驗驗證)的一部分。

  • (錯誤)為了通過參數將某些內容傳遞回調用者,您必須使用指向指針的指針。
  • (錯誤) (int) ptr cast 是不可移植的,並且很明顯是縮小轉換的罪魁禍首。
  • (錯誤)在將ptr的內容分配給某個地方之前,您不能打印它。 在賦值之前不能打印nextptr指向的內容。 您不能打印 null 指針的值。
  • (設計)沒有理由將size作為指針傳遞,因為您沒有在 function 內部更改它。
  • (設計)將malloc的結果轉換為void*是沒有意義的。
  • (設計)從void*轉換為void*是沒有意義的。
  • (設計)如果傳遞 NULL 指針, realloc的行為類似於malloc 由於您的 function 顯然假定在第一次調用期間傳遞的指針始終初始化為 null 指針,因此您可以利用它來簡化代碼。
  • (可能的錯誤)或者,如果傳遞的指針初始化,則您的代碼完全錯誤 - 您不能使用未初始化的指針作為參數調用realloc

刪除所有錯誤和混亂后,您的代碼可能如下所示:

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>

// NOTE: *nextptr must be initialized to null outside this function!
int memalloc_ (int** nextptr, int size)

{
  void *ptr;
  printf("Address of *nextptr:%p\n", (void*)*nextptr);
         
  ptr = realloc(*nextptr, size); 
  if (ptr == NULL) {
      return -1;
  }
  *nextptr = ptr;
  printf("Address pointed by ptr (Value stored in ptr): %p\n", ptr);
  printf("Address of nextptr:%p\n", (void*)*nextptr);
  return 0;
}

即使在舊的 C90 中也應該可以編譯。

暫無
暫無

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

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