Default values on arguments in C functions and fun

2019-01-17 21:39发布

问题:

Converting a C++ lib to ANSI C and it seems like though ANSI C doesn't support default values for function variables or am I mistaken? What I want is something like

int funcName(int foo, bar* = NULL);

Also, is function overloading possible in ANSI C?

Would need

const char* foo_property(foo_t* /* this */, int /* property_number*/);

const char* foo_property(foo_t* /* this */, const char* /* key */, int /* iter */);

Could of course just name them differently but being used to C++ I kinda used to function overloading.

回答1:

No, Standard C does not support either. Why do you feel you need to convert your C++ code to C? That could get quite tricky - I'd have thought writing wrappers would be the way to go, if your C++ must be callable from C.



回答2:

Nevertheless I found a "trick" to do so if you use GCC.

GCC has a handy ## extension on variadic macro that allows you to simulate a default argument.

The trick has limitations: it works only for 1 default value, and the argument must be the last of you function parameters.

Here is a working example.

#include <stdio.h>


#define SUM(a,...) sum( a, (5, ##__VA_ARGS__) )

int sum (a, b)
  int a;
  int b;
{
  return a + b;
}


main()
{

  printf("%d\n", SUM( 3, 7 ) );

  printf("%d\n", SUM( 3 ) );

}

In this case, I define SUM as a call to sum with the default second argument being 5.

If you call with 2 arguments (first call in main), it would be prepocessed as: sum( 3, (5, 7) );

This means:

  • 1st argument is 3
  • second argument is the result of the sequence (5, 7)... which is obviously 7!

As gcc is clever, this has no effect on runtime as the first member of the sequence is a constant and it is not needed, it will simply be discarded at compile time.

If you call with only one argument, the gcc extension will remove the VA_ARGS AND the leading coma. So it is preprocessed as:

sum( 3, (5 ) );

Thus the program gives the expected output:

10
8

So, this does perfectly simulate (with the usual macro limitations) a function with 2 arguments, the last one being optional with a default value applied if not provided.



回答3:

As far as I know ANSI C doesn't directly support function overloading or default arguments. The standard substitute for overloading is adding suffixes to the function name indicating the argument types. For example, in OpenGL, a "3fv" suffix to a function name means the function takes a vector of three floats.

Default arguments can be viewed as a special case of function overloading.



回答4:

There is a way to support as many default parameters you need, just use a structure.

// Populate structure with var list and set any default values
struct FooVars {
  int int_Var1 = 1;  // One is the default value
  char char_Command[2] = {"+"};
  float float_Var2 = 10.5;
};
struct FooVars MainStruct;

//...
// Switch out any values needed, leave the rest alone
MainStruct.float_Var2 = 22.8;
Myfunc(MainStruct);  // Call the function which at this point will add 1 to 22.8.
//...

void Myfunc( struct FooVars *MyFoo ) {
  switch(MyFoo.char_Command) {
    case '+':
      printf("Result is %i %c %f.1 = %f\n" MyFoo.int_Var1, MyFoo.char_Command, MyFoo.float_Var2, (MyFoo.float_Var2 + MyFoo.int_Var1);
      break;
    case '*':
      // Insert multiply here, you get the point...
      break;
    case '//':
      // Insert divide here...
      break;
  }
}


回答5:

Try this.

#include <stdio.h>
#include <stdarg.h>

/* print all non-negative args one at a time;
   all args are assumed to be of int type */
void printargs(int arg1, ...)
{
  va_list ap;
  int i;

  va_start(ap, arg1); 
  for (i = arg1; i >= 0; i = va_arg(ap, int))
    printf("%d ", i);
  va_end(ap);
  putchar('\n');
}

int main(void)
{
   printargs(5, 2, 14, 84, 97, 15, 24, 48, -1);
   printargs(84, 51, -1);
   printargs(-1);
   printargs(1, -1);
   return

 0;
}


回答6:

Neither of default values or function overloading exists in ANSI C, so you'll have to solve it in a different way.



回答7:

You can't so easily since C does not support them. The simpler way to get "fake overloading" is using suffixes as already said... default values could be simulated using variable arguments function, specifying the number of args passed in, and programmatically giving default to missing one, e.g.:

 aType aFunction(int nargs, ...)
 {
   // "initialization" code and vars
   switch(nargs)
   {
     case 0:
         // all to default values... e.g.
         aVar1 = 5; // ...
         break;
     case 1:
         aVar1 = va_arg(arglist, int); //...
         // initialize aVar2, 3, ... to defaults...
         break;
     // ...
   }
 }

Also overloading can be simulated using var args with extra informations to be added and passed and extracode... basically reproducing a minimalist object oriented runtime ... Another solution (or indeed the same but with different approach) could be using tags: each argument is a pair argument type + argument (an union on the whole set of possible argument type), there's a special terminator tag (no need to specify how many args you're passing), and of course you always need "collaboration" from the function you're calling, i.e. it must contain extra code to parse the tags and choose the actual function to be done (it behaves like a sort of dispatcher)



回答8:

You'll have to declare each C++ overloaded function differently in C because C doesn't do name mangling. In your case "foo_property1" "foo_property2".



回答9:

i think u can use a function with variable arguments here is my example

#include <stdarg.h>
#include <stdio.h>
void baz( int flag, ... )
{
    va_list ap;
    char *bar = "baz"; /* default value */
    va_start( ap, flag );
    if ( flag == 1 )
        bar = va_arg( ap, char * );
    va_end( ap );
    printf( "%s\n", bar );
}
int main( void )
{
    baz( 0 );
    baz( 1, "foo");
    baz( 2 );
    baz( 1, "bar");
    return 0;
}

the output is

baz
foo
baz
bar

if u look for example man 2 open they say

SYNOPSIS
       #include <sys/types.h>
       #include <sys/stat.h>
       #include <fcntl.h>

       int open(const char *pathname, int flags);
       int open(const char *pathname, int flags, mode_t mode);

       int creat(const char *pathname, mode_t mode);

       int openat(int dirfd, const char *pathname, int flags);
       int openat(int dirfd, const char *pathname, int flags, mode_t mode);

but mode is actually a ... argument