Wednesday, March 23, 2011

Using __arglist with a varying set of named parameters

Hi, in my application I have 2 layers. The first layer is a C legacy exposing cdecl functions that use the "..." syntax for a varying parameter list. The only way I found to call these functions from my .Net layer (the second one) is using the DllImport technics. For example the C function below:

int myFunc(char* name, ...);

looks like that in C#:

[DllImport("MyDll.dll"),
 CharSet = CharSet.Ansi,
 CallingConvention = CallingConvention.Cdecl]
int myFunc(string name, __arglist);

My problem is that sometimes I want to call this function with 2 extra parameters but if one of them is NULL it won't be included in the argument list (my legacy code fails on NULL values). For example I want this call:

int foo(string name, string a, string b)
{
     myFunc(name, __arglist(a, b));
}

{
     foo("john", "arg1", null);
}

to be interpreted by C as

myFunc("john", "arg1");

Unfortunately doing something like that:

int foo(string name, string a, string b)
{
     List<string> args = new List<string>();
     if(a != null) args.Add(a);
     if(b != null) args.Add(b);
     myFunc(name, __arglist(args));
}
{
     foo("john", "arg1", null);
}

is interpreted by C like that:

myFunc(name, args);

and not:

myFunc(name, args[0]);

Does anybody have any idea?

From stackoverflow
  • How does the C function know which one is the last parameter? It cannot know a priori how many parameters there are. It needs additional information. One common way for functions get the information they need is by parsing the included string parameter to count format specifiers, as in printf. In that case, if the format string only indicates that there is one extra parameter, then the function doesn't know the difference between a call that really had just one extra parameter and a call that had two or a call that had 20. The function should have the self-discipline to only read one parameter, since that's all the format string said there was. Reading more would lead to undefined behavior.

    If what I've described is not the way your function works, then there's not much you can do on the calling end to solve it. But if it is how your function works, then there's nothing to do on the calling end, because there's no problem.

    Another option, since you indicate that your "legacy code fails on null values," is to fix your legacy code so it doesn't fail anymore.

    A third option is to simply write all four possibilities:

     if (a != null) {
       if (b != null)
         return myFunc(name, a, b);
       else
         return myFunc(name, a);
     } else {
       if (b != null)
         return myFunc(names, b);
       else
         return myFunc(names);
     }
    

    More than two optional parameters, though, and the code starts getting unwieldy.

0 comments:

Post a Comment