Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

ISO_C_BINDING and Visual C

popovdmitrya
Beginner
1,083 Views
Hi! It took me a call from Fortran, some function of the static libraries in C. I used ISO_C_Binding, began to investigate, but three calls upeshen only one. What am I doing wrong?

[cpp]//C static lib. code
#include

//Calling of this function succes
void show(int x){
printf("Value = %dn",x);
}

//And other functions return wrong results
double copyVal(double A){
printf("C: A = %fn",A);
return A;
}



double getSum(int sz,double Arr[]){
int k = 0;
double Sum = 0;

printf("C: sz = %dn",sz);
printf("C: n");
for(k = 0; k[/cpp]
And Fortran code:

[plain]module mod_CData
use, intrinsic :: iso_c_binding;

implicit none;

interface
!void show(int x)
subroutine Show(x) bind(C,name = "show")
use, intrinsic :: iso_c_binding;
implicit none;

integer(c_int), value, intent(in) :: x;
end subroutine Show;

!double getSum(int sz,double *Arr)
real(c_double) function GetSum(sz, A) bind(C,name="getSum")
use, intrinsic :: iso_c_binding;
implicit none;

integer(c_int), value, intent(in) :: sz;
real(c_double), dimension(:) :: A;
end function GetSum;

!double copyVal(double A)
real(c_double) function CopyVal(x) bind(C,name = "copyVal")
use, intrinsic :: iso_c_binding;
implicit none;

integer(c_double), value :: x;
end function CopyVal;
end interface;


end module mod_CData


program Test_binding

use mod_CData;
integer(4), parameter :: M = 10;
integer(4) :: test_val;

real(8) :: res;
real(8),target,dimension(1:M) :: Arr;
real(8),pointer,dimension(:) :: pArr;

test_val = 10;

call Show(test_val);


print *,"c_int = ",c_int;
print *,"c_double",c_double;



Arr = (/10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0/);

print *,'Arr:'
print *,Arr;
pArr => Arr;

res = GetSum(size(Arr), pArr);

print *,'Res = ',res;

print *,'CopyVal = ', CopyVal(dble(100.0_8));

read(*,*);
end program Test_binding


Sorry for bad english.
Best regards, Dmitry

P.S. Visual Studio 2005 + Intel Fortran 10.1

Example project link: http://stream.ifolder.ru/11315393[/plain]
0 Kudos
7 Replies
Steven_L_Intel1
Employee
1,083 Views
In your Fortran interface for CopyVal, you declared the argument as integer(C_DOUBLE). You want real(C_DOUBLE) instead. The compiler should have given you an error similar to this:

t.f90(67): warning #6075: The data type of the actual argument does not match the definition. [DBLE]
print *,'CopyVal = ', CopyVal(dble(100.0_8));
------------------------------^

When you fix the declaration, you can also remove the "dble" from the call - just pass 100.0_8 (or 100.0_C_DOUBLE), though the dble is harmless here.
0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,083 Views
Quoting - popovdmitrya
Hi! It took me a call from Fortran, some function of the static libraries in C. I used ISO_C_Binding, began to investigate, but three calls upeshen only one. What am I doing wrong?
[plain]    
!double getSum(int sz,double *Arr)
real(c_double) function GetSum(sz, A) bind(C,name="getSum")
use, intrinsic :: iso_c_binding;
implicit none;

integer(c_int), value, intent(in) :: sz;
real(c_double), dimension(:) :: A;
end function GetSum;
[/plain]

In addition, you can not use assumed-shape (:) arrays when interfacing with C. You need an assumed-size array (*) instead.

Steve, I think that the compiler should issue a warning in such cases, both for routines and INTERFACE blocks.

(Edit: In this particular case, it will happen to just work, because the array address is the first field in the array descriptor, but in principle it should be prohibited, as it may cause various nasty run-time errors)
0 Kudos
Steven_L_Intel1
Employee
1,083 Views
I don't agree that it should be prohibited. The C routine could read the descriptor (we document it.) A proposed TR for F2008 adds support for C code to deal with Fortran descriptors in an implementation-independent fashion. But I agree that only explicit-shape or assumed-size arrays are "interoperable" by the terms of F2003, and the compiler could warn about non-interoperable arguments if standards checking was enabled. I'm somewhat uncomfortable with warning about this by default, though I can see the benefits in some cases.
0 Kudos
popovdmitrya
Beginner
1,083 Views
Thank you. Unfortunate typographical error, I found myself. Of course real (C_DOUBLE). So I tried to pass assumed-size array (*) instead of assumed-shape (:), but it still causes problems. Everything is working correctly after I began to pass a pointer to an array using C_PTR (fortran_array). But in this case is controlled by the situation that transferred real (C_DOUBLE), rather than, say, integer (C_LONGINT) or logical (1)?

Here's how I did:

[cpp]#include 
typedef struct CStruct{
    int a;
    int b;
    char ch;
    double c[10];
} TCStruct;
TCStruct globalS;
void show(int x){
    printf("C: Value = %dn",x);
}//show
int returnValue(int x){
    printf("C: Value = %dn",x);
return x;
}
void showArray(const int sz, double Arr[]){
    int i = 0;
    
    printf("sz = %dn",sz);
    for(i = 0; i);
    }
}//showArray
void getStruct(TCStruct *S){
    int l;
    S->a = globalS.a*2;
    S->b = globalS.b*3;
    S->ch = globalS.ch +'0';
    for(l = 0;l<10;l++){
        S->c = globalS.c;
    }
    printf("C: Struct is Get with differencen");
}//getStruct
void setStruct(TCStruct S){
    int l;
    
    printf("C: Struct is setn");
    
    globalS.a = S.a;
    globalS.b = S.b;
    globalS.ch = S.ch;
    for(l = 0;l<10;l++){
        globalS.c = S.c;
    }
}//getStruct[/cpp]
Fortran Interface:

[plain]module mod_CInterfaces
use, intrinsic :: iso_c_binding;
implicit none;
type CStructure
    sequence
    
    integer(c_int) :: a;
    integer(c_int) :: b;
    character :: ch;
    real(c_double),dimension(10) :: c;
end type;
interface
    subroutine Show(x) bind(C,name = "show")
        use, intrinsic :: iso_c_binding;
        
        integer(c_int), value, intent(in) :: x;
    end subroutine Show;
    
subroutine ShowArray(sz, Arr) bind(C,name = "showArray") use, intrinsic :: iso_c_binding; integer(c_int), value, intent(in) :: sz; type(c_ptr), value, intent(in) :: Arr; end subroutine ShowArray;
integer(c_int) function ReturnValue(x) bind(C,name = "returnValue") use, intrinsic :: iso_c_binding; integer(c_int), value, intent(in) :: x; end function ReturnValue; subroutine GetStruct(S) bind(C,name='getStruct') use, intrinsic :: iso_c_binding; type(c_ptr), value :: S; end subroutine GetStruct; subroutine SetStruct(S) bind(C,name='setStruct') use, intrinsic :: iso_c_binding; implicit none; type CStructure sequence integer(c_int) :: a; integer(c_int) :: b; character :: ch; real(c_double),dimension(10) :: c; end type; type(CStructure), value, intent(in) :: S; end subroutine SetStruct; end interface; end module mod_CInterfaces[/plain]
And Fortran program

[plain]program Test_binding
use mod_CInterfaces;
implicit none;
integer(4), parameter :: sz = 22;
integer(4) :: test_val;
real(8), dimension(:), allocatable :: Arr;
type(CStructure) :: S;
test_val = 10;

call Show(test_val);
print *,'Fortran: test_val = ',test_val;

test_val = ReturnValue(test_val+sz);
print *,'Fortran: test_val = ',test_val;

allocate(Arr(1:sz));
Arr = 100.0;

call ShowArray(sz, c_loc(Arr));
deallocate(Arr);
S%a = 10;
S%b = 20;
S%ch = 'a';
S%c = (/1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 0.0/);

call SetStruct(S);

call GetStruct(c_loc(S));
write(*,*) 'Fortran: ',S;
print *,'press ENTER';
read(*,*);
end program Test_binding[/plain]

0 Kudos
popovdmitrya
Beginner
1,083 Views
And when the Intel Fortran will be full support for the standard 2003?
0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,083 Views
Quoting - popovdmitrya
# subroutine SetStruct(S) bind(C,name='setStruct')
# use, intrinsic :: iso_c_binding;
# implicit none;
#
# type CStructure
# sequence
#
# integer(c_int) :: a;
# integer(c_int) :: b;
# character :: ch;
# real(c_double),dimension(10) :: c;
# end type;
#
# type(CStructure), value, intent(in) :: S;
# end subroutine SetStruct;

1) You used SEQUENCE in the Fortran definition of the type. This has the side effect that it turns member packing to 1-byte (because SEQUENCE means it can be sequence-associated), so CStructure%C in Fortran follows immediately CStructure%ch, while in C there is 3-byte padding after ch. Get rid of the SEQUENCE. I think that you can use BIND(C) attribute for the structure, in which case you should have got a compiler warning (though I didn't check it myself)

2) You probably used SEQUENCE to workaround double-definition/interface block scope problem. That's a wrong cure in this case. Instead, use IMPORT keyword within the above-quoted INTERFACE block, to import the declaration of CStruct into the scope.
0 Kudos
popovdmitrya
Beginner
1,083 Views
Quoting - Jugoslav Dujic
Quoting - popovdmitrya
# subroutine SetStruct(S) bind(C,name='setStruct')
# use, intrinsic :: iso_c_binding;
# implicit none;
#
# type CStructure
# sequence
#
# integer(c_int) :: a;
# integer(c_int) :: b;
# character :: ch;
# real(c_double),dimension(10) :: c;
# end type;
#
# type(CStructure), value, intent(in) :: S;
# end subroutine SetStruct;

1) You used SEQUENCE in the Fortran definition of the type. This has the side effect that it turns member packing to 1-byte (because SEQUENCE means it can be sequence-associated), so CStructure%C in Fortran follows immediately CStructure%ch, while in C there is 3-byte padding after ch. Get rid of the SEQUENCE. I think that you can use BIND(C) attribute for the structure, in which case you should have got a compiler warning (though I didn't check it myself)

2) You probably used SEQUENCE to workaround double-definition/interface block scope problem. That's a wrong cure in this case. Instead, use IMPORT keyword within the above-quoted INTERFACE block, to import the declaration of CStruct into the scope.
Not quite so. I used SEQUENCE because such recommendations were met in the books published in their native language. I actually confronted with the fact that the char incorrectly referred to the C. Thanks for the clarification
0 Kudos
Reply