繁体   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