You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

64位环境下Fortran调用C动态内存分配的地址截断问题求助

64位机器下Fortran77调用C内存分配的地址截断问题解决方法

问题背景

一套老旧大型研究代码中,Fortran77子程序getmem.F调用C程序memalloc.c实现动态内存分配,在64位机器使用PGI 2020.4编译器编译时出现内存访问错误。调试发现:C中分配的64位内存地址(如0x2aaaaaad9010)被强制转换为32位int类型后截断,返回给Fortran的ptr值仅保留低32位,导致无法正确访问内存。

原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 (截断后的错误值)
      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代码片段

#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);
}

解决方法

核心是使用64位整数类型存储内存地址,避免32位类型的截断问题,同时保证Fortran和C的类型匹配:

1. 修改Fortran代码中的指针类型

将ptr的声明从integer ptr改为integer*8 ptr(Fortran77中integer*8表示64位有符号整数,可完整存储64位地址):

integer memalloc, memfree
      integer*8 ptr  ! 改为64位整数类型
      integer size, ierr0

2. 修改C代码的参数类型与赋值逻辑

  • 将int *nextptr改为long long *nextptr(C中long long是64位整数,与Fortran的integer*8匹配)
  • 赋值时将指针转换为long long而非int,避免截断
  • 调整NULL判断为*nextptr == 0(long long类型与指针类型NULL直接比较会有警告,0对应初始空指针状态)
  • realloc时将*nextptr转换为void*,保证类型正确

修改后的C代码:

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

int memalloc_ (long long *nextptr, int *size)  // nextptr改为long long*
{
  void *ptr;

  printf("Address of nextptr:%p \nValue of nextptr: %lld \n", nextptr, *nextptr);

  /* Before Memory Allocation */
  printf("Address pointed by ptr (Value stored in ptr): %p \n", (void*)ptr);
         
  if (*nextptr == 0) {  // 替换NULL判断为0,匹配long long类型
    if ((ptr = malloc(*size)) == NULL) {
      return(-1);
    }
  }
  else {
    if ((ptr = realloc((void*)*nextptr, *size)) == NULL) {  // 显式转换为void*
      return(-1);
    }
  }

  printf("Address pointed by ptr (Value stored in ptr): %p \nValue when printed as a long integer %lld \n", 
         (void*)ptr, (long long)ptr);

  *nextptr = (long long)ptr;  // 转换为long long存储完整64位地址

  printf("Address of nextptr:%p \nValue of nextptr: %lld \n", nextptr, *nextptr);
  printf("Value of nextptr in long format: %lld \n", *nextptr);

  return (0);
}

原理说明

64位系统中内存地址长度为64位,原代码中使用32位int(Fortran的integer)存储地址,必然导致高位截断。改用64位整数类型后,可完整保存64位地址值,保证Fortran能正确接收并使用分配的内存地址。


内容的提问来源于stack exchange,提问作者Surya Sarvajith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 15:50:38