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
相关产品推荐
相关产品推荐

