Fortran Coder

查看: 12978|回复: 6
打印 上一主题 下一主题

[混编] fortran的空指针问题(调用C函数)

[复制链接]

62

帖子

14

主题

0

精华

专家

F 币
557 元
贡献
326 点
跳转到指定楼层
楼主
发表于 2015-8-28 19:22:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 安靖 于 2015-8-29 21:58 编辑

在fortran中调用c的函数,其中有参数应为NULL值。我在fortran中用的是内置函数NULL(),但是发现在传到c里就变成0,何解?
以下为c/c++中对NULL的定义
[C] 纯文本查看 复制代码
/* Define NULL pointer value */
#ifndef NULL
#ifdef __cplusplus
#define NULL    0
#else
#define NULL    ((void *)0)
#endif
#endif



fortran中NULL()应该是使指针未关联,而不是所谓的空指针。

我猜测就是这个原因。 那么问题来了,怎么解决呢?
是否可以这样
在fortran中声明变量,调用C使变量地址为NULL,然后再将声明的变量所谓参数传给C的函数呢

我是在调用metis库的时候遇到的这个问题,我暂时的解决办法是直接修改metis(C函数),已经满足我现在的需求了。
那现在我把测试代码贴出来,看看有没有不用修改metis的方法,顺便大家讨论学习。
附件为测试代码以及用到的metis库(版本为5.1.0)

[Fortran] 纯文本查看 复制代码
program main
        implicit none
        integer,parameter :: nvtxs=15,Edges=22
        integer :: xadj(nvtxs+1),adjncy(2*Edges)
        integer :: part(nvtxs)
        integer :: npart = 2
        !***********metis 4.0.1***********
        integer :: option(5) = [ 0, 0, 0, 0, 0 ]
        integer :: edgecut
        integer :: wgtflag = 0
        integer :: numflag = 1
        integer :: vwgt, adjwgt
        !***********metis 5.1.0************
        integer :: ncon =1
        integer :: options(40)
        integer :: objval
        
        !**********Graph Data**************
        xadj=[0, 2, 5, 8, 11, 13, 16, 20, 24, 28, 31, 33, 36, 39, 42, 44]
        adjncy=[1, 5, 0, 2, 6, 1, 3, 7, 2, 4, 8, 3, 9, 0, 6, 10, 1, 5, 7, 11, 2, 6, 8, 12, 3, 7, 9, 13, 4, 8, 14, 5, 11, 6, 10, 12, 7, 11, 13, 8, 12, 14, 9, 13]
!***********metis 4.0.1***********
!参数vwgt,adjwgt等传0值进去就行了。
!        call METIS_PartGraphRecursive(nvtxs,xadj,adjncy,vwgt,adjwgt,wgtflag,numflag,npart,option, edgecut, part)   

        !***********metis 5.1.0************
!会提示错误。原因是参数NULL()在c中(NULL()==NULL)不成立
        call METIS_SetDefaultOptions(options)
        options(18) =1
        call METIS_PartGraphRecursive(nvtxs,ncon,xadj,adjncy,NULL(), NULL(), NULL(), npart, &
         & NULL(), NULL(), options,objval,part)
        write(*,*) '**********************'
        write(*,*) part
        write(*,*) '**********************'
end program main


makefile
[Make] 纯文本查看 复制代码
TARGET  = test.out
GC        = ifort
CFLAGS  = -fpp -g 
SOR        = metis_test.f90
OBJS        = metis_test.o
LIBS    = ~/lib/libmetis.a
$(OBJS):
        @echo "-----------------------------------"
        @echo "Compiling..."
        @echo "-----------------------------------"
        @$(GC) $(CFLAGS) -c $(SOR) $(INCLUDE)
        @echo "-----------------------------------"
        @echo "Linking..."
        @echo "-----------------------------------"
        @$(GC) $(CFLAGS) -o $(TARGET) $(OBJS) $(LIBS)
        @echo "-----------------------------------"
        @echo "Deleting OBJ files..."
        @echo "-----------------------------------"
        @rm -fr *.o 
        @echo "-----------------------------------"
clean:
        @rm -fr *.o 
        @rm -fr $(TARGET)








metis_test.f90

1.07 KB, 下载次数: 0

测试代码

libmetis-5.1.0.tar

650 KB, 下载次数: 0

metis5.1.0库

分享到:  微信微信
收藏收藏 点赞点赞 点踩点踩

2033

帖子

12

主题

5

精华

论坛跑堂

臭石头雪球

F 币
1641 元
贡献
709 点

美女勋章热心勋章星光勋章新人勋章贡献勋章管理勋章帅哥勋章爱心勋章规矩勋章元老勋章水王勋章

沙发
发表于 2015-8-29 08:49:33 | 只看该作者
在我的编译器上。这俩是一样的。NULL() 与空指针。
实际上呢,一块内存,或一个地址,只有 2**N 种可能(N位位数)。至于如何解释它,是编译器的事情。
对于同样的 0x00000000,可以解释为 integer 0 可以解释为 real 0 可以解释为 NULL(),也可以解释为空指针。
(大多数语言和编译器都把 NULL() 视为 0x00000000,但反过来 0x00000000 不一定是 NULL())

在混编中,实际参与混编的只是内存(或地址)。两边各自负责对内存或地址做出解释。所以,不必让两边的解释一样,只要让实际传递的内存(或地址)一样就可以了。

举个例子,同样一个结构体。Fortran 可以是
[Fortran] 纯文本查看 复制代码
type ST
  real :: a(4)
end type ST

传递给 C/C++,它可以认为是
[C] 纯文本查看 复制代码
struct ST {
  float a , b , c , d;
}

所以。如果 C 语言需要一个空指针,那么 Fortran 给他一个 0x00000000 就可以了。
不管是 integer 0 还是 real 0 还是 NULL() ,甚至如果是32位,还可以是 char(0)//char(0)//char(0)//char(0)
C 语言并不知道 fortran 如何解释这个 0x00000000

62

帖子

14

主题

0

精华

专家

F 币
557 元
贡献
326 点
板凳
 楼主| 发表于 2015-8-29 10:06:33 | 只看该作者
fcode 发表于 2015-8-29 08:49
在我的编译器上。这俩是一样的。NULL() 与空指针。
实际上呢,一块内存,或一个地址,只有 2**N 种可能(N ...

谢谢回复
我的fortran编译器是ifort版本是11.0,c语言编译器是gcc4.6.3
把fortran的NULL()传到c里后

NULL()不等于NULL
不知道你用什么编译器?

954

帖子

0

主题

0

精华

大师

F 币
184 元
贡献
75 点

规矩勋章元老勋章新人勋章水王勋章热心勋章

QQ
地板
发表于 2015-8-29 10:24:09 来自移动端 | 只看该作者
给出你的代码及编译命令或make

490

帖子

4

主题

0

精华

大宗师

F 币
3298 元
贡献
1948 点

水王勋章元老勋章热心勋章

5#
发表于 2015-8-31 19:12:48 | 只看该作者
本帖最后由 pasuka 于 2015-8-31 19:58 编辑

按照gfortran手册的说法
http://gcc.gnu.org/onlinedocs/gfortran/ISO_005fC_005fBINDING.html
直接用下面两个中任意一个都可以的
Moreover, the following two named constants are defined:
Name        Type
C_NULL_PTR        C_PTR
C_NULL_FUNPTR        C_FUNPTR
Both are equivalent to the value NULL in C.代码参考
[C] 纯文本查看 复制代码
#include "stdio.h"

int test(int *a, int num)
{
        if(!a){
                printf("This is null pointer\n");
        }
        else{
                for(int i=0; i<num; i++){
                        printf("Array[%d]=%d\n", i+1, a[i]);
                }
        }
        return 0;
}


[Fortran] 纯文本查看 复制代码
program main
use, intrinsic:: iso_c_binding
implicit none
interface
        integer(c_int) function func(array, n) bind(c, name="test")
        import
        implicit none
        integer(c_int), intent(in), value:: n
        integer(c_int), intent(in):: array(n)
        end function
        
        integer(c_int) function func2(pt, n) bind(c, name="test")
        import
        implicit none
        integer(c_int), intent(in), value:: n
        type(c_ptr), value:: pt
        end function
end interface

type(c_ptr) :: a1
integer(c_int), target:: abc(5)
integer:: i

abc = [12, 12, 35, 67, 11]
a1 = c_loc(abc(1))
! Pass array directly
i = func(abc, size(abc))
! Pass address
i = func2(c_loc(abc(1)), 5)
! Pass null pointer
i = func2(c_null_ptr, 5)
! Pass null function pointer
i = func2(c_null_funptr, 5)
end program

69

帖子

7

主题

0

精华

专家

F 币
320 元
贡献
224 点
6#
发表于 2015-9-2 13:11:01 | 只看该作者
Fortran与C混合编程应该采用5楼pasuka这种方式。Fortran的c_null_ptr对应C的null指针,因此在C函数中使用null指针的地方可以直接使用c_null_ptr,Fortran的c_null_funptr用于函数指针,对于一般的数据不应采用。

62

帖子

14

主题

0

精华

专家

F 币
557 元
贡献
326 点
7#
 楼主| 发表于 2015-9-2 16:24:06 | 只看该作者
jason388 发表于 2015-9-2 13:11
Fortran与C混合编程应该采用5楼pasuka这种方式。Fortran的c_null_ptr对应C的null指针,因此在C函数中使用nu ...

metis库已经给出了fortran接口了
您需要登录后才可以回帖 登录 | 极速注册

本版积分规则

捐赠本站|Archiver|关于我们 About Us|小黑屋|Fcode ( 京ICP备18005632-2号 )

GMT+8, 2024-12-25 21:58

Powered by Tencent X3.4

© 2013-2024 Tencent

快速回复 返回顶部 返回列表