简体   繁体   中英

c function to return one of two possible types

I currently use three different functions to return a numeric value (one returns a double , the other two return a long ):

int main(void)
{
   // lots of code

    dRate = funcGetInterestRate();
    lMonths = funcGetTerm();
    lPrincipal = funcGetPrincipal();

    // lots of code

    return 0;
}

The three functions code is about 90% the same so I would like to consolidate into 1 function. I want to pass a value flag to a single function something like this:

  1. if "1" passed, determine interest rate, return a double
  2. if "2" passed, determine term of loan, return a long
  3. if "3" passed, determine principal of loan, return a long

I only want to return 1 value ever from the function when it is called, but the value I want to return can be either a double or a long . I want to do something like this:

void funcFunction(value passed to determine either long or double)
{
   // lots of code

   if (foo)
      return double value;
   else
      return long value;
}

Is there an easy way to do this?

A function's return type is fixed at compile time. You can't change the return type based on the parameters you pass in.

However, since your main goal is to remove repeated code in the functions and consolidate them, this can be addressed in a different way. In other words, this is an XY problem .

What you can do in your case is extract the common code in each of your three functions into a separate function, then the three original functions can call the common function to do most of the work, then extract the part they need and return that.

For example:

struct loan {
    double rate;
    long term;
    long principal;
};

void calcLoan(struct loan *loan)
{
    // do stuff
    loan->rate = // some value        
    loan->term = // some value        
    loan->principal = // some value        
}

double funcGetInterestRate()
{
    struct loan loan;
    calcLoan(&loan);
    return loan.rate;
}

long funcGetTerm()
{
    struct loan loan;
    calcLoan(&loan);
    return loan.term;
}

long funcGetPrincipal()
{
    struct loan loan;
    calcLoan(&loan);
    return loan.principal;
}

No, C does not allow this. The return type is in the function declaration (which you have as void).

Slightly easier is to provide two pointers to variables and indicate which one to use in the return value:

int funcFunction(yourArgument, long *longResult, double *dblResult)
{
   // lots of code

   if (foo)
   {
      *dblResult = value;
      return 1;
   } else
   {
      *longResult = otherValue;
      return 0;
   }
}

(And possibly you can even use a union .) However ... I had to use value and otherValue as inside the function you cannot use the same variable to hold either a long or a double . You can – again, with a union – but this is stressing the eaze of having only one single function to the breaking point.

You might consider returning some tagged union . The Glib GVariant type could be inspirational, and since Glib is free software, you could study its source code. See also this answer .

So you would declare some public struct with an anonymous union inside:

struct choice_st {
   bool islong;
   union {
     long i; // valid when islong is true
     double d; // valid when islong is false
   }
}

and you could return a value of that struct choice_st .

struct choice_st res;
if (foo) {
  res.islong = true;
  res.i = somelong;
  return res;
} 
else {
  res.islong = false;
  res.d = somedouble;
  return res;
}

You might also decide to use C dynamic memory allocation , return a freshly malloc -ed pointer to struct choice_st , and adopt a convention about who is responsible of free -ing that pointer. (BTW, GVariant is doing something similar to this).

You sort of can do this. It's easier to show than explain, but I'll add an explanation if this isn't clear:

void add_or_divide_by_xor(unsigned int a, unsigned int b, unsigned short c,
                          unsigned long *add, unsigned double *divide) {
    unsigned int xor = a ^ b;
    if (add != NULL) {
        *add = xor + c;
    }
    if (divide != NULL) {
        *divide = (double)xor / (double)c;
    }
}

Called:

unsigned long add;
unsigned double divide;
add_or_divide_by_xor(5, 17, 4, &add, NULL);
add_or_divide_by_xor(17, 6, 4, NULL, &divide);

Depending on your platform, double might be a superset of long . You should already know whether this is true (because you know what your algorithms do, and what their possible output values are); if you don't, consider the following:

  • double can represent integers up to 2 53 exactly
  • long is either a 32-bit or a 64-bit type

So if your long values are 32-bit, you can just always return double from your functions, and cast it to long outside your functions, where needed.

You could try something like this.

#include <stdio.h>

void* func1(int key){
  static double interest;
  static long term;
  static long principle;

  //your common code to modify values of interest, term and principle
  //
  //Let us give them some dummy values for demonstration
  interest = 34.29347;
  term = 5843535;
  principle = 7397930;

  //conditions
  if(key == 1){
    return &interest;
  }
  else if(key == 2){
    return &term;
  }else if(key == 3){
    return &principle;
  }else printf("%s\n","error!!");
}

int main()
{
    printf("%f\n",*(double*)func1(1));
    printf("%ld\n",*(long*)func1(2));
    printf("%ld\n",*(long*)func1(3));
    func1(4);
    return 0;
}

Output

34.293470

5843535

7397930

error!!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM