функция c для возврата одного из двух возможных типов - PullRequest
0 голосов
/ 30 декабря 2018

В настоящее время я использую три разные функции для возврата числового значения (одна возвращает double, две другие возвращают long):

int main(void)
{
   // lots of code

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

    // lots of code

    return 0;
}

Код трех функций составляет около 90%то же самое, поэтому я хотел бы объединить в 1 функцию.Я хочу передать флаг значения одной функции примерно так:

  1. , если «1» пройдено, определить процентную ставку, вернуть double
  2. , если «2» прошло, определить срок кредита, вернуть long
  3. , если «3» прошло, определить основную сумму кредита, вернуть long

Я хочу вернуть только 1 значениеиз функции, когда она вызывается, но значение, которое я хочу вернуть, может быть либо double, либо long.Я хочу сделать что-то вроде этого:

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

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

Есть ли простой способ сделать это?

Ответы [ 6 ]

0 голосов
/ 30 декабря 2018

Возможно, вы захотите вернуть теговое объединение .Тип Glib GVariant может быть вдохновляющим, и, поскольку Glib является свободным программным обеспечением, вы можете изучить его исходный код.См. Также этот ответ .

Таким образом, вы объявите некоторую общедоступную struct с анонимным union внутри:

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

, и вы можете вернуть значениечто 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;
}

Вы можете также решить использовать C динамическое выделение памяти , вернуть только что malloc -веденный указатель на struct choice_st и принять соглашение окто несет ответственность за free -ing этот указатель.(Кстати, GVariant делает что-то похожее на это).

0 голосов
/ 30 декабря 2018

Вы можете попробовать что-то вроде этого.

#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;
}

Вывод

34.293470

5843535

7397930

ошибка !!

0 голосов
/ 30 декабря 2018

В зависимости от вашей платформы double может быть надмножеством long.Вы уже должны знать, верно ли это (потому что вы знаете, как работают ваши алгоритмы и каковы их возможные выходные значения);если вы этого не сделаете, рассмотрите следующее:

  • double может представлять целые числа до 2 53 точно
  • long является либо 32-битовый или 64-битный тип

Так что, если ваши long значения 32-битные, вы всегда можете просто вернуть double из ваших функций и привести его к long вне ваших функцийгде необходимо.

0 голосов
/ 30 декабря 2018

Вы вроде можете это сделать.Проще показать, чем объяснить, но я добавлю объяснение, если это не ясно:

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;
    }
}

Вызывается:

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);
0 голосов
/ 30 декабря 2018

Нет, C не позволяет этого.Тип возвращаемого значения находится в объявлении функции (которое у вас есть как void).

Немного проще предоставить два указателя на переменные и указать, какой из них использовать в возвращаемом значении:

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

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

(И, возможно, вы даже можете использовать union.) Однако ... Мне пришлось использовать value и otherValue как внутри функцию, которую вы не можете использовать так жепеременная для хранения long или a double.Вы можете - опять же, с помощью union - но это подчеркивает легкость наличия только одной функции до предела.

0 голосов
/ 30 декабря 2018

Тип возврата функции фиксирован во время компиляции.Вы не можете изменить тип возвращаемого значения на основе параметров, которые вы передаете.

Однако, поскольку ваша главная цель - удалить повторяющийся код в функциях и объединить их, это может быть решено по-другому.Другими словами, это проблема XY .

В вашем случае вы можете извлечь общий код каждой из ваших трех функций в отдельную функцию, а затем три исходные функции.может вызвать общую функцию для выполнения большей части работы, затем извлечь нужную часть и вернуть ее.

Например:

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...