Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

reading c variables in fortran 2

Status
Not open for further replies.

monkeycode

Technical User
Jan 24, 2012
7
GB
I'm editing a model written in C and fortran- I've worked out how to use fortran variables in C, but not the reverse- any advice on what I'm doing wrong, or links to info on how to do this greatly appreciated- I don't even know the basics, like should I be using pointers (it seems to fall over when I do...)

I've added the module below to the C code, and I want to read obdc with the fortran component which calls this


C:
#include <stdio.h>
#include <stdlib.h>
#include "n2o_model.h"
#include "soilwater.h"
#include <math.h>

extern LAYERPAR_SPT layers;
void bd_till(float *bdc, float obdc)
{
	int ilyr;
	printf("till*");
/*	  calcualte organic matter for tillage calculation*/
 obdc = (layers->orgfrac[0]*layers->width[0] +
                 layers->orgfrac[1]*layers->width[1] +
                 layers->orgfrac[2]*layers->width[2]) /
                (layers->width[0] + layers->width[1] + layers->width[2]);
	  printf("obdc %8.6f\n", obdc);

 
               
for (ilyr=0; ilyr < layers->numlyrs; ilyr++) {


	
	layers->bulkd[ilyr] = layers->bulkd[ilyr] + *bdc;

}
/*		printf("bdc = %8.6f\n", *bdc);printf("layers->bulkd[%1d] = %8.6f\n", ilyr, layers->bulkd[ilyr]);
printf("layers->bulkd[%1d] = %8.6f\n", ilyr, layers->bulkd[ilyr]);
bdc= *cultbd[1] + *cultbd[2] * layers->clayfrac[1] + *cultbd[3] * 
      (1- (layers->clayfrac[1] + layers->sandfrac[1])) + *cultbd[4] * layers->sandfrac[1] 
	  + *cultbd[5] * layers->orgfrac[1]; printf("bd_till");	
printf("cultbd[1] = %8.6f\n",cultbd[1]);
printf("layers->clayfrac[%1d] = %8.6f\n", ilyr, layers->clayfrac[1]);bulkden = bulkden * *bdc;
printf("bulkden = %8.6f\n",*bulkden);*/
return;
}

the fortran component calling this is quite long, but the relevant bits

Code:
c ... Fortran to C prototype
      INTERFACE

	  SUBROUTINE bd_till(bdc, obdc)
          !MS$ATTRIBUTES ALIAS:'_bd_till' :: bd_till
          REAL    bdc
	    REAL    obdc
        END SUBROUTINE bd_till
   END INTERFACE
	   call bd_till(bdc, obdc)	
   print *, "obdc", obdc

Thanks!
 
I am not exceptionally good in reading and understanding C-codes, so I cannot check if there is a glitch in this code.

On the first glimpse I found the following:

Compared to the usage in C, Fortran passes values by reference not by value as does C. So what the C-routine receives when called by the fortran routine is a pointer unless you set it otherwise. So I think it should be

void bd_till(float *bdc, float *obdc)

if you want to call your c-procedure the fortran way.

If you want to pass the data by value - the standard C-usage - then you should include something in your interface that defines passing data by value. I do not know about your compiler but the compiler directive should include some keyword like 'STDCALL', or 'VALUE' which are the keywords in my compiler.

Your line

!MS$ATTRIBUTES ALIAS:'_bd_till' :: bd_till

would be

!DEC$ ATTRIBUTES STDCALL, ALIAS :'_bd_till' :: bd_till

in my environment. Guess the only difference are in the tag to make this a compiler directive (!MS instead of !DEC) , but I am not sure about this. Then of course you should omit the '*' in the declaratuion of your C-procedure.

See if either of the two option works.

Norbert



The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.
 
The examples you've given are for Powerstation/CVF/IVF and Microsoft C.

Which C/Fortran compilers are you using. Interfacing is different for different compilers unless you're using Fortran 2003 onwards.
 
If you're using CVF/IVF

!DEC$ATTRIBUTES

is the same as

!M$ATTRIBUTES

If you are using PS4, then you can only use !M$ATTRIBUTES.
 

altering the call from Fortran caused a crash (but I do feel I have been educated so thanks for that anyway, always good to be learning!!) I think because I'm using PS4, so it should have been !M$ATTRIBUTES as xwb suggests
but anyway, I went back and tried putting the pointers in the C code, which was causing a crash yesterday, but works fine today- obviously I was doing something different...
so success!Thanks!!
 
As gummibaer says, the routines need to be stdcall. It is to do with the way the compiler works.

By default, C routines are __cdecl. This means that the caller is responsible for taking the parameters off the stack. If it is __stdcall, the callee is responsible for taking the parameters off the stack. Languages like Fortran and Pascal use __stdcall.

If it is not __stdcall, the program will call the C routine correctly but fall over when it returns. If you are using printfs, call fflush(stdout) before you return. C I/O and Fortran I/O are on completely different streams so the C output may appear on the screen long after the Fortran output.

If you have the full PS4 installation, have a look in the section on Mixed Language programming.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top