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

Calling C from fortran

Lars_Jakobsen
Beginner
665 Views
Hi,
I have previously had succes with asking questions about an fortran to c interface, so here goes another one.

I am trying to call a function in a C compiled library file (this is obtained from third party)called hasp_login that will take as input two integers and a string and return an integer stating if login successeeded or not (along with a handle).

The C header file looks like this:

typedef hasp_u32_t hasp_handle_t;
typedef hasp_u32_t hasp_feature_t;

typedef void *hasp_vendor_code_t;

hasp_status_t HASP_CALLCONV hasp_login(hasp_feature_t feature_id,
hasp_vendor_code_t vendor_code,
hasp_handle_t *handle);

Now thefeature_id looks like this inc

#define HASP_DEFAULT_FID 0

#define HASP_PROGNUM_OPT_CLASSIC 0x00001000

#define HASP_FEATURETYPE_MASK 0xffff0000

#define HASP_PROGNUM_DEFAULT_FID (HASP_DEFAULT_FID | HASP_PROGNUM_FEATURETYPE)

const hasp_feature_t feature = HASP_PROGNUM_DEFAULT_FID | HASP_PROGNUM_OPT_CLASSIC;

and the vendor_code something like
unsigned char vendor_code[] =
"IHTKDNCKDKDK"
"DKDKJTKDKDLS"
"KDOSKJ((/1212J"
"KKDI";

finaly the handle is of type hasp_handle_t and the call to make in C is

status = hasp_login(feature,(hasp_vendor_code_t *)vendor_code,&handle);

This all works fine, however I would like to do this from fortran, so I have made:


integer, parameter :: HASP_DEFAULT_FID = z'00000000'

integer, parameter :: HASP_PROGNUM_FEATURETYPE = z'ffff0000'

integer, parameter :: HASP_PROGNUM_OPT_CLASSIC = z'00001000'

integer, parameter :: HASP_PROGNUM_DEFAULT_FID = IOR(HASP_PROGNUM_FEATURETYPE,IOR(HASP_DEFAULT_FID,HASP_PROGNUM_OPT_CLASSIC))

interface hasp_login

function hasp_login(feature_id, vendor_code, handle)

!DEC$ ATTRIBUTES REFERENCE, ALIAS:'_hasp_login@12' :: hasp_login

!DEC$ ATTRIBUTES VALUE :: feature_id

!DEC$ ATTRIBUTES REFERENCE :: vendor_code

!DEC$ ATTRIBUTES VALUE :: handle

integer*4 :: feature_id

integer*4 :: vendor_code

integer*4 :: handle

end function

end interface

!character*41 :: vendor_code
character, dimension(41) :: vendor_code

vendor_code"IHTKDNCKDKDK" // &

"DKDKJTKDKDLS" // &
"KDOSKJ((/1212J" // &
"KKDI"C

and the call

status = hasp_login(HASP_PROGNUM_DEFAULT_FID, loc(vendor_code), handle)

where handle is an integer.

However this does not work i.e. the C libraryshould have contacted my license manager and performed a login.

Any suggestions?

Regards

Lars

0 Kudos
6 Replies
mecej4
Honored Contributor III
665 Views
A general technique that I would use in such situations:

1. Run the pure C version and record the function argument types and values just before and after entry to hasp_login, using a debugger or by inserting printf() statements.

2. Write a dummy replacement for hasp_login with the same interface, link it with the Fortran caller, and run using a debugger. If the observed types and values do not match those recorded in Step 1, fix the code.

3. Replace the dummy routine with the actual routine. Test.
0 Kudos
anthonyrichards
New Contributor III
665 Views
You need to explain exactly what 'it does not work' means. What are the error messages during the compile/link/build/execution steps?

On the Fortran side, you have not defined the type of Function Hasp_Login. It might be best to write a C-wrapper function for Hasp_Login that actually uses integer references that can be called from Fortran.

The use of a string argument complicates things. If the memory allocation for the string buffer is made on the C-side, I would tend to send the buffer address AND the buffer length (including terminating null character) to the Fortran so that it can write your required login text into it (but not overrun the buffer!).
0 Kudos
GVautier
New Contributor II
665 Views
Hello

In C/Fortran mixed programming, it is important to understand which argument should be declared reference and which should be value.

In C, your call is
status = hasp_login(feature,(hasp_vendor_code_t *)vendor_code,&handle);

So it indicates that you pass the address of the variable "handle".

So in fortran, I think that you should declare handle as REFERENCE and not VALUE. I suppose that this function returns a value in handle so it must be passed by reference.

0 Kudos
Lars_Jakobsen
Beginner
665 Views
Thank you all for replying.

mecej4:
This sounds as a good idea and I will look into this.

anthonyrichards:
Just to clarify whatI mean by "it does not work". My fortran program compiles, links and builds fine, however during execution it does not succeed in performing a login at my licens manager. Since my program written in C (just used for testing, this is not to be used in my fortran program) can call the c-library just fine and did make a login at my license manager I think that it is my fortran interface that is wrong i.e. I am not sending the correct values/references to C. I know when ever I write something like "it does not work", I always end up leaving out some important info - so hopefully this made it more clear.

You are correct that I did not define the type of the function Hasp_Login. I tried this i.e. the function is now defined as an integer. This hadthe effectthat Inow am able to read the returned error message (which states that the vendor_code is invalid i.e. my text string is not recieved by the c libraryas intended).

Your last point aboutmemory allocation on the c-side will force me to writing a c-wrapper(or am I missing the point)? I have thought aboutthat, but beeing quite the novice in C, Iwas hopingI could just fixtheinterface in fortran.

gvautier:
I think you are right. I have changed theinterface and now declares the handle as REFERENCE.

So after implementing the changes (definition of the type Hasp_Login and declaring the handle by REFERENCE), I am left with a returned error code during executionstating that my vendor_code is invalid.

I am troubled by the definition of the type hasp_vendor_code_t:
typedef void *hasp_vendor_code_t;

Would this need special attention in my interface (why is the type defined as void)?

Again thanks for all the input.

Regards

Lars

0 Kudos
IanH
Honored Contributor II
665 Views
I think you've gone one too many levels of indirection on the vendor_code argument. The LOC intrinsic gets the address of your vendor string, then the REFERENCE attribute in the declaration says to pass the address of that address. The C declaration says it just wants an address (void*).

I suggest you change the declaration of vendor_code to have the VALUE attribute.
0 Kudos
Lars_Jakobsen
Beginner
665 Views
You are right. Changing the declaration from reference to value made it work.

Comming from fortran I have always found the concept of "level of indirection" tricky - I think I will need to read up on this.

Thank you very much

-Lars
0 Kudos
Reply