[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Problems with IDL call_external to C shared object
- Subject: Re: Problems with IDL call_external to C shared object
- From: "Mark Rivers" <rivers(at)cars.uchicago.edu>
- Date: Thu, 12 Oct 2000 21:50:57 -0500
- Newsgroups: comp.lang.idl-pvwave
- Organization: The University of Chicago
- References: <39E5E704.CF772370@psi.ch>
- Xref: news.doit.wisc.edu comp.lang.idl-pvwave:21689
I've done a lot of this, and it's not that hard, don't give up!
Here are some tricks:
- All arrays which need to be passed between IDL and C must be allocated in
IDL, as J.D. Smith said. This includes both arrays being passed from IDL to
C and from C back to IDL. Sometimes this requires an initial call to the C
code to return the array sizes which IDL will allocate, if the array sizes
are not known to IDL beforehand.
- Don't deallocate any arrays which were passed from IDL.
- Don't pass strings, rather pass byte arrays. It is much simpler. Convert
strings to byte arrays in IDL before or after the CALL_EXTERNAL call.
- Convert all output variables to the data type which C is expecting in the
CALL_EXTERNAL call.
>- What is the effect of the /CDECL keyword to CALL_EXTERNAL ?
>I tried with and without but no success.
This controls the calling convention. If your C function is being called
then you probably have this set correctly.
>- Is it possible that the C program "forgets" something between
>the IDL CALL_EXTERNALs ?
- As J.D. Smith said, it will forget anything which is not global or static.
>- How can I return an array via CALL_EXTERNAL or have I always
>to loop over calls returning scalars ? The EZCA library (channel
>access to EPICS control system) manages to return arrays, but I
>couldn't figure out how.
My EZCA code is rather opaque, since it uses macros which allow it to work
on both IDL and PV-WAVE, on Unix, VMS and Windows.
Here is a simple example. It is C code which computes the Mandelbrot set,
and is called from IDL.
argv[7] is a 2-D array.
void mandelbrot(int argc, void *argv[])
{
int nr = *(int *) argv[0];
int ni = *(int *) argv[1];
double rstart = *(double *) argv[2];
double istart = *(double *) argv[3];
double dr = *(double *) argv[4];
double di = *(double *) argv[5];
int max_iter = *(int *) argv[6];
int *result = argv[7];
int i, j, count;
double real, imag, rz, iz, sz2, rz2, iz2;
for (i=0; i<ni; i++) {
imag = istart + i*di;
for (j=0; j<nr; j++) {
real = rstart + j*dr;
rz = 0.;
iz = 0.;
sz2 = 0.;
count = 0;
while ((count < max_iter) && (sz2 < 4.0)) {
rz2 = rz * rz;
iz2 = iz * iz;
iz = 2.0 * rz * iz + imag;
rz = rz2 - iz2 + real;
sz2 = rz2 + iz2;
count++;
}
*result++ = count;
}
}
}
Here is the IDL code which calls the C code:
function mandelbrot1, xcenter, ycenter, radius, size, max_iter, xout, yout
if (n_elements(size) eq 0) then size=100
if (n_elements(max_iter) eq 0) then max_iter=255
dx = double(radius)*2/size
xstart = double(xcenter - radius)
xstop = double(xcenter + radius)
ystart = double(ycenter - radius)
ystop = double(ycenter + radius)
result = lonarr(size, size)
xout = xstart + findgen(size)*dx
yout = ystart + findgen(size)*dx
s = call_external('mandelbrot.dll', 'mandelbrot', $
long(size), $
long(size), $
double(xstart), $
double(ystart), $
double(dx), $
double(dx), $
long(max_iter), $
result)
return, result
end