В C вернуть 2 переменные из функции - PullRequest
0 голосов
/ 05 июля 2018

По сути, у меня есть функция C, которая печатает определенные числа, и я также хочу, чтобы функция возвращала 2 значения. Я попробовал это с помощью struct, но я не сделал это правильно, и я не уверен, как поступить. Я прочитал другие вопросы и понимаю, что было бы лучше использовать указатель, но я не уверен, как это сделать.

Мой код C выглядит следующим образом:

struct re_val
{
    double predict_label;
    double prob_estimates;
    predict_label = 5.0;
    prob_estimates = 8.0;
};

int c_func(const char* dir, double a, double b, double c, double d)
{
    double x[] = { a, b, c, d };

    printf("x[0].index: %d \n", 1);
    printf("x[0].value: %f \n", x[0]);

    printf("x[1].index: %d \n", 2);
    printf("x[1].value: %f \n", x[1]);

    printf("x[2].index: %d \n", 3);
    printf("x[2].value: %f \n", x[2]);

    printf("x[3].index: %d \n", 4);
    printf("x[3].value: %f \n", x[3]);

    return re_val;
}

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

Я на самом деле вызываю эту функцию в python через ctypes, и моя функция python включена ниже.

calling_function = ctypes.CDLL("/home/ruven/Documents/Sonar/C interface/Interface.so")
calling_function.c_func.argtypes = [ctypes.c_char_p, ctypes.c_double, ctypes.c_double, ctypes.c_double, ctypes.c_double]
calling_function.c_func.restype =  ctypes.c_double
y = calling_function.c_func("hello",1.1, 2.2, 3.1, 4.2)
print y

Ответы [ 3 ]

0 голосов
/ 05 июля 2018

Обычно это делается со структурами. Чтобы инициализировать его в стеке, сделайте что-то вроде этого.

#include <stdio.h>  /* printf */
#include <assert.h> /* assert */

struct sample {
    float x[4];
};

struct re_val {
    float predict_label, prob_estimates;
};

/** Returns the re_val of x. */
static struct re_val c_func(const struct sample *const x) {
    struct re_val rv;
    float a;
    assert(x); /* Debug warn if called with null. */
    rv.predict_label = (x->x[0] + x->x[1]) * 5.0f;
    a = x->x[2] + x->x[3];
    if(a < 0.01f) a = 0.01f;
    rv.prob_estimates = 1.0f / a;
    return rv;
}

/** Prints the re_val. */
static void print(const struct re_val *const rv) {
    assert(rv);
    printf("# prediction label\tprobability estimates\n%g\t%g\n",
        rv->predict_label, rv->prob_estimates);
}

int main(void) {
    const struct sample x = { { 0.1f, 0.2f, 1.0f, 100000.0f } };
    const struct re_val rv = c_func(&x);
    print(&rv);
    return 0;
}

См. Эту ссылку Есть ли недостатки в передаче структур по значению в C, а не в передаче указателя? ; в частности, прототип мог бы быть static void c_func(const struct sample *const x, struct re_val *const rv); там, где заполнен указатель rv, особенно если re_val - это большая структура или кто-то хочет, чтобы она потенциально размещалась в куче.

Существуют различные способы передачи информации из функции, например,

  • возвращение в стек, как здесь. Обычно это хорошо для структур, отпечаток памяти которых тривиален. div, strtod64;
  • передача указателя на данные, которые должны быть заполнены. fread, fscanf, snprintf, sprintf, strfmon, strncat, strncpy, strptime, strftime, asctime_r, ctime_r, localtime_r;
  • , сохраняющий static struct - этот метод не вводится повторно и перезаписывает одни и те же данные несколько раз. Это не потокобезопасно. asctime, ctime, gmtime, localtime, strtok;
  • имеет тип, связанный с состоянием, которое необходимо передать для выполнения операций, FILE *: fopen / fclose, regex_t: regcomp / regfree или глобальный, errno: perror;
  • возвращает выделенный в куче указатель, который пользователь должен освободить. Например, asprintf.
0 голосов
/ 05 июля 2018

Этот ответ является альтернативой использованию структур - что, конечно, допустимо - вы можете вернуть несколько значений по ссылке / через указатель. И отвечает на главный вопрос, можно ли вернуть множественное значение из одной функции.

#include<stdio.h>

void sum_diff(double a, double b, double* sum, double*diff)
{
    if (sum) // Only assign when we have a valid reference
        *sum = a + b;
    if (diff)
        *diff= a - b;
}

int main() {

    double diff, sum;
    double a = 4, b = 3;

    sum_diff(a, b, &sum, &diff);

    fprintf(stdout, "The sum of %lf and %lf is %lf\n", a, b, sum);
    fprintf(stdout, "The difference of %lf and %lf is %lf\n", a, b, diff);

    return 0;
}

Функция sum_diff назначает использует аргументы a, b, sum и diff. a и b являются входными аргументами, а sum и diff являются выходными аргументами. Обратите внимание, что функция проверяет, являются ли значения sum и diff не равными NULL, это позволяет вызывающему абоненту дополнительно получать разность или сумму. Это может быть удобно при более сложных вычислениях.

0 голосов
/ 05 июля 2018

Сначала вам нужно определить свою структуру:

struct re_val{
    float predict_label;
    float prob_estimates;
};

А затем вам нужно вернуть struct re_val из вашей функции:

struct re_val c_func(const char* dir, float a, float b, float c, float d )
{
    /* ... all that stuff ... */

    struct re_val r;
    r.predict_label = 5.0f;
    r.prob_estimates = 8.0f;   
    return r;
}

Таким образом, полный пример будет:

struct re_val{
    float predict_label;
    float prob_estimates;
};

struct re_val c_func(const char* dir, float a, float b, float c, float d )
{

    /* ... all that stuff ... */

    struct re_val r;
    r.predict_label = 5.0f;
    r.prob_estimates = 8.0f;   
    return r;
}

int main(void)
{
    struct re_val r = c_func("",1.0f,2.0f,3.0f,4.0f);
    printf("predict_label=%.1f\n",r.predict_label);
    printf("predict_label=%.1f\n",r.prob_estimates);
    return 0;
}

Попробуйте здесь: http://rextester.com/WRROW32352

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...