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

Variable values "unstable" after return from C routine

michael_green
Beginner
924 Views

My first attempt at mixed language programming is working but I'm obviously missing some crucial step because weird things happen to the values of some variables after I return to Fortran. For example, I want to get the number of rows and columns in a TIFF image so I call a C routine with the following interface ...

interface
subroutine c_get_tiff_size(fullname,pnrows,pncols,pcOK)
!DEC$ ATTRIBUTES C :: c_get_tiff_size

character(*) fullname

integer*4 nrows,ncols
logical cOK

!DEC$ ATTRIBUTES REFERENCE :: fullname,pnrows,pncols,pcOK
pointer (pnrows,nrows),(pncols,ncols),(pcOK,cOK)

end subroutine c_get_tiff_size
end interface

Outside the interface declaration I have ...

integer*4 ncols,nrows

pointer (pncols,ncols),(pnrows,nrows)

And my call to the c routine is ...

call c_get_tiff_size(fullname,pncols,pnrows,pcOK)

At frst, on return, the values of ncols and nrows are correct, but a few lines further on, after some seemingly irrelevant call, the values become fantastically wrong. It's not the particular call that causes this effect because other calls have the same effect on other variables. I can get around the problem by immediately capturing the values in other local variables, but this is a poor solution. I presume the problem has something to do with the fact that both ncols and nrows are pointees, but I don't know what to do about it. Please can someone explain?

With many thanks in advance,

Mike

0 Kudos
5 Replies
joerg_kuthe
Novice
924 Views
Can you provide the C prototype of that function, such that we can see what kind of arguments are to pass?
Have you checked that those pointers (pnrows, pncols, pcOK) remain unaltered?
From what you say, I would guess, that the pointers are changing their values and so, those pointees (nrows, ncols,cOK) are changing their addresses. While stepping further on in your program, you might want to check what is happening to their addresses by calling the LOC(arg) function (which returns the address of its argument).
Joerg

0 Kudos
michael_green
Beginner
924 Views
Here's the C function ...
extern "C" void c_get_tiff_size (char* fullname,
uint32* &pncols,
uint32* &pnrows,
uint32* &pcOK)
{
TIFF *tif;
uint32 cOK;

//Supress warnings about unknown tags, i.e. georeferences tags, etc
TIFFErrorHandler oldhandler;
oldhandler = TIFFSetWarningHandler(NULL);

//Open tiff file for reading
tif = TIFFOpen(fullname, "r");
if(tif) {
uint32 ncols,nrows;

cOK = 1;
pcOK = &cOK;
//Get image width (number of columns).
if (TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &ncols) == 0)
{
cOK = 0;
return;
}
//Get image height (number of rows).
if (TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &nrows) == 0)
{
cOK = 0;
return;
}
pncols = &ncols;
pnrows = &nrows;
TIFFClose(tif);
}
else
{
cOK = 0;
pcOK = &cOK;
}
}

Thanks
Mike
0 Kudos
GVautier
New Contributor III
924 Views

Hello

You have used pointers (pnrows,pncols, pcOk) that are assigned in the stack of the C function so the addresses become invalid after the return to the caller.

I propose a more simple implementation :

Interface

interface
logical*4 function c_get_tiff_size(fullname,nrows,ncols)
!DEC$ ATTRIBUTES C :: c_get_tiff_size

character(*) fullname

integer*4 nrows,ncols

!DEC$ ATTRIBUTES REFERENCE :: fullname,nrows,ncols

end function c_get_tiff_size
end interface

Variables declaration

integer*4 ncols,nrows

logical*4 cOk

CALL

cOk=c_get_tiff_size(fullname,ncols,nrows)

C function

extern "C" int c_get_tiff_size (char *fullname,
uint32 *ncols,
uint32 *nrows)
{
TIFF *tif;
int cOk=FALSE; // 0

//Supress warnings about unknown tags, i.e. georeferences tags, etc
TIFFErrorHandler oldhandler;
oldhandler = TIFFSetWarningHandler(NULL);

//Open tiff file for reading
tif = TIFFOpen(fullname, "r");
if(tif)

{

//Get image width (number of columns).
if (TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, ncols) != 0)

{
//Get image height (number of rows).
if (TIFFGetField(tif, TIFFTAG_IMAGELENGTH, nrows) != 0)

cOk=TRUE;// 1

}

TIFFClose(tif);
}

return(cOk);

}

0 Kudos
michael_green
Beginner
924 Views
Many thanks for your neat and simple solution, it works very well. As must have been obvious, this is my first ever attempt at writing C code.
I have usedyour simplerversion as a model for recoding a similar, but slightly more complex C function, with mixed results. Within the C routine, everything looks OK, and the variables have the correct values. But on the Fortran side, I cannot get REAL*8 values of anything other than zero, so I guess it's the interface that's wrong.
The interface is ...
interface
logical*4 function c_get_tiff_header(fullname,emin,nmax,nrows,ncols,de,dn)
!DEC$ ATTRIBUTES C :: c_get_tiff_header

character(*) fullname

integer*4 nrows,ncols
real*8 emin,nmax,de,dn

!DEC$ ATTRIBUTES REFERENCE :: fullname,emin,nmax,nrows,ncols,de,dn

end function c_get_tiff_header
end interface

With variables declared as ...
character*256 fullname
integer*4 nrows,ncols
real*8 emin,nmax,de,dn
And call to C routine ...
cOK = c_get_tiff_header(fullname,emin,nmax,ncols,nrows,de,dn)
The C routine is ...
extern "C" int c_get_tiff_header (char *fullname,
double *xorig,
double *yorig,
uint32 *ncols,
uint32 *nrows,
double *dx,
double *dy)
{
TIFF *tif;
int OK = FALSE;

//Supress warnings about unknown tags, i.e. georeferences tags, etc
TIFFErrorHandler oldhandler;
oldhandler = TIFFSetWarningHandler(NULL);

//Open tiff file for reading
tif = TIFFOpen(fullname, "r");
if(tif) {
double *origin = 0;
double *cellsize = 0;
uint16 count;

//Get origin (centre dot of upper left pixel). 33922 is "MultiTiePointTag" ("GeoreferenceTag").
if (TIFFGetField(tif, 33922, &count, &origin)!=0)
{
xorig = &origin[3];
yorig = &origin[4];
}
else
{
return(OK);
}

//Get pixel size. 33550 is "ModelPixelScaleTag".
if (TIFFGetField(tif, 33550, &count, &cellsize)!=0)
{
dx = &cellsize[0];
dy = &cellsize[1];
}
else
{
return(OK);
}

//Get image width (number of columns).
if (TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, ncols)== 0)
{
return(OK);
}

//Get image height (number of rows).
if (TIFFGetField(tif, TIFFTAG_IMAGELENGTH, nrows)== 0)
{
return(OK);
}

TIFFClose(tif);
OK = TRUE;
return(OK);
}
}

On return from this function, on the Fortran side, ncols and nrows have the correct values, but emin, nmax, de, and dn all have values of zero. Do you have any further suggestions?

With many thanks

Mike

0 Kudos
GVautier
New Contributor III
924 Views

You are confusing variables and pointers.

in C langage :

int dummy;

dummy is a variable

&dummy is the address of the content of the dummy variable

if you want to change the value of dummy write dummy="something";

int *dummy;

dummy is a pointer

so if you write

dummy="something" you set the pointer value

*dummy="something" you set the value pointed by dummy.

So in you C functions, if you want to return a value proceed as below :

void myfunction(int *dummy) // dummy is a pointer

*dummy="something"; // set the value pointed by dummy

In your code you wrote

dummy=&"something"; // does'nt change the value pointed by dummy but change the pointer value.

I think it is better for you learn more about C pointers in a C test application before using them in mixed langage.

0 Kudos
Reply