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

String Length Argument and arrays

mountain_ike
Beginner
1,141 Views

This may sound a bit complex, but here is my problem.  I am in the process of building a project that needs to use netcdf.  I'm using an older build (3.6.3), which, when I build it with Fortran bindings requires the compiler switch '/iface:mixed_str_len_arg' to work correctly.  I'm building them into static libraries so I can then include these in another project where I build a fortran DLL that.  I then call this new DLL from a C# program.  Passed variables all work now, except for arrays.  They get passed into the C# program at the correct length, but the elements in the array are all 'Undefined address'.  If I leave off the '/iface:mixed_str_len_arg' compiler switch, the NETCDF libraries won't work, and the string then get clobbered in the pass.  And none of these problems existed until I added in these NETCDF libraries...without them everything works fine - except I need them for my project.  Any thoughts?  Am I going about this totally backwards?  I am using Visual Fortran Composer XE 2011 with Visual Studio 2010.

0 Kudos
12 Replies
Steven_L_Intel1
Employee
1,141 Views

My advice is to not use /iface, which changes the interface for all calls. Instead, declare INTERFACE blocks for the netcdf routines and add:

!DEC$ ATTRIBUTES MIXED_STR_LEN_ARG :: routinename

in each one. I'm a bit puzzled though - I would not expect a library to want that unless it was also using STDCALL. (Maybe you're using that and didn't mention it.)

I'm also puzzled about arrays being significant. Can you show some actual code with declarations on both the Fortran and C# side? Could it be that the arrays are not declared in C# in a manner consistent with Fortran?

0 Kudos
mountain_ike
Beginner
1,141 Views

Steve,

   I miss spoke about the strings - I've got them passing correctly now.  However, that compiler switch is the thing that is messing with my array pass.  I am pretty far outside of my comfort zone, and I like the idea of the interface, so I'll give that a shot.  My calls are fairly simple.  The C# pass looks like this:

//Import DLL here

        [DllImport(@"Fortran_Built.dll",
            CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        static extern void FORTSUB(ref float t0,  ref float rh,
                                           [MarshalAs(UnmanagedType.LPStr)] string String1,
                                           [MarshalAs(UnmanagedType.LPStr)] string String2,
                                           float[] Array, ref int ierr);

with the call like this:

   float t0=10.0f;
   float rh=75.0f;
   string inString1='This is the first string';
   string inString2='This is the second string';

   float[] array1= new float[31];
   for (int i = 0; i < 31; i++)
       {
           array1 = 40.0f - i;
       }

   int ierr=0;

   
   FORTSUB(ref t0, ref rh, inString1, inString2, array1, ref ierr);

The fortran is as follows:

      subroutine FORTSUB(t0, rh, String1, String2, array1, ierr)      
 
  !DEC$ ATTRIBUTES DLLEXPORT::FORTSUB
  !DEC$ ATTRIBUTES ALIAS 'FORTSUB':FORTSUB    !This makes the DLL call available to other programs       
  !We will try passing the string by reference
  !DEC$ ATTRIBUTES REFERENCE::String1
  !DEC$ ATTRIBUTES REFERENCE::String2
      
      character*255 String1,String2
      real t0,rh
      real array1(31)
      integer ierr

 

 

0 Kudos
Steven_L_Intel1
Employee
1,141 Views

Add REFERENCE on the ATTRIBUTES line for the subroutine. By using /iface:mixed_str_len_arg, you get a length even with REFERENCE on the argument. It's weird, I know.

0 Kudos
mountain_ike
Beginner
1,141 Views

I made that change (!DEC$ ATTRIBUTES REFERENCE::ARRAY1), with a similar 'pass by reference' in the C# but it did not have any effect.  Am I misunderstanding you?  Is the problem that the array comes after the strings?

0 Kudos
Steven_L_Intel1
Employee
1,141 Views

I want you to change:

!DEC$ ATTRIBUTES ALIAS 'FORTSUB':FORTSUB  

to:

!DEC$ ATTRIBUTES REFERENCE, ALIAS 'FORTSUB':FORTSUB  

0 Kudos
mountain_ike
Beginner
1,141 Views

Sorry, my mistake.  However, making that change had no effect.  The array still comes through to the fortran subroutines with the correct dimension, but every element says 'Undefined address'.  I'll try working the Interface angle and see what that does.  Thanks for your help on this!

0 Kudos
Steven_L_Intel1
Employee
1,141 Views

Maybe the issue is that the way you have the argument declared in C# isn't compatible with Fortran arrays. I am not familiar enough with C# to comment on that. In C I'd pass an array as "float *" or something like that. Do you know how C# is passing the array? (I assume you know that Fortran arrays are 1-based.)

0 Kudos
mountain_ike
Beginner
1,141 Views

I'm fair at C#, and I've done lots of C# - Fortran integration.  It works surprisingly easy (and yes, I make sure all passed arrays are 1D).  This all worked beautifully before I added in the NETCDF libraries...If I don't include those, I don't need the weird compiler directives (none of which seem to work), and everything works smoothly.  I am thinking it falls back on the NETCDF build I am using, but I have had a really hard time coming up with a build I can do through VS...there is an incredible amount of info on building NETCDF, but almost nothing for building it through VS.  I want to be able to test with 32 bit and 64 bit builds.  Without reliable NETCDF libraries, this project won't go anywhere.  And I am TERRIBLE at C programming, so it is really hard for me to try to pick through the build I do have..all very frustrating.

0 Kudos
Steven_L_Intel1
Employee
1,141 Views

One thought - what other compiler options are you using, and which compiler was your NETCDF library built for? If you are mixing STDCALL and C, you will get stack corruption that can cause odd problems.

0 Kudos
mountain_ike
Beginner
1,141 Views

Everything was built through MSVS 2010 with the fortran compiles XE 2011.  I did NOT set the STDCALL and C directives.

0 Kudos
Steven_L_Intel1
Employee
1,141 Views

But what about NETCDF? Can you provide a link to the exact library download you're using?

0 Kudos
mountain_ike
Beginner
1,141 Views

I followed the step-by-step instruction for building NETCDF 3.6.3 from the appendix D of the following link (http://www.fredwobus.com/research/wobus_2013_PhD_thesis_dense_water_cascading.pdf).  As I've mentioned, NETCDF is out of my comfort zone.  I the past I've used pre-built versions, but now I need a little more control.

0 Kudos
Reply