7

Is there a way to declare a C variadic function and call it from Fortran? I need to call this function to compute some dot products between vectors labeled with a string. My idea was to declare something like the following, where the variable list of arguments contains string literals. If the variable list of arguments is empty, then I would do a lookup among the standard labels and perform the calculation. If the user specified two labels I would retrieve those two vectors and get their dot product:

extern "C" void compute_dot_product(double * dot_product, ...)
{
    va_list args;
    va_start(args, NULL);
    char * label1 = va_arg(args, char *);
    if (!label1)
    {
       // Do standard label lookup and compute dot product
    }
    else
    {
       // Compute dot product between the vectors with the specified labels
       char * label2 = va_arg(args, char *);
    }
    va_end(args);
}

the only problem is that I can compile my C library and link it to a Fortran executable, but I get a runtime error when I try to access the variable list of arguments. Any idea if what I am trying to do is possible? A possible solution would then be to split into two functions: one that does the standard label lookup (0 argument case), the other that handles the non-standard label lookup (2 argument case). I would rather avoid this solution though.

Kara
  • 6,115
  • 16
  • 50
  • 57
boberto
  • 151
  • 8
  • It needs to be declared as cdecl on both sides. Your runtime error may be because one side is stdcall and the other is cdecl. – cup Dec 17 '13 at 22:45

1 Answers1

4

It is not possible to call a variadic function in a standard conforming (i.e. portable) way.

You could make the definition of the C function take two parameters only (so it is no longer variadic - existing references to the function would need to be modified), with the second parameter in the C function a pointer, either NULL to indicate that there are no additional things being passed, or pointing at an array of pointers (perhaps NULL terminated) or whatever, with any additional things. In F201X an interface body for this sort of function might be able to use the OPTIONAL attribute for the second argument.

IanH
  • 21,026
  • 2
  • 37
  • 59
  • That is what a variadic function does. See: http://stackoverflow.com/a/19171063/1162141 – technosaurus Oct 30 '13 at 04:15
  • 1
    @technosaurus I don't see the relevance of the comment or linked answer. – IanH Oct 30 '13 at 04:36
  • The "..." in a variadic function is essentially an array of pointers (though they can be integral types) The link shows the somewhat complicated way these casts are done to get the right type starting with the first pointer. So your answer makes sense as a replacement for "..." +1. – technosaurus Oct 30 '13 at 04:51
  • I do not get why this interface works then integer function printf(format, item1, item2) bind(C) import character(kind=c_char) :: format(*) integer(c_int), value :: item1, item2 end function – Vladimir F Героям слава Oct 30 '13 at 08:47
  • You asking me? If so 'works' /= 'standard conforming', but you know that. – IanH Oct 30 '13 at 09:49
  • I am definitely not an expert in C nor in variadic functions. I really assumed this is the right way before. – Vladimir F Героям слава Oct 30 '13 at 12:22
  • 1
    I mean I allways assumed the variadic arguments are passed like all other ones (by value) and the routine just uses the format string to see how many of them are pushed on the stack (or in registers) and how to interpret them. – Vladimir F Героям слава Oct 30 '13 at 12:32
  • Ok,now I get it.You (or technosaurus) were not describing how variadic functions work, but how to make their alternative. – Vladimir F Героям слава Oct 30 '13 at 16:54
  • 1
    In my case - yes - that was my intent - I'll reword things to make that clear. Your "assumed" understanding about how variadic functions could be [and nearly always are?] implemented is the same as mine - the macros for accessing them just walk back up the stack. I don't think they typically are implemented by passing an array of pointers. I think you'd need a pretty exotic C compiler for that to work. But I'm not a C or Fortran compiler person - I just blindly follow the language rules. – IanH Oct 30 '13 at 20:45