2

Basically, I have a C function that prints out certain numbers and I also want the function to return 2 values. I have tried this out using struct but I did not do this correctly and I am not sure how to proceed. I have read other questions and I understand that using a pointer would be better but I am not sure how to.

My C code is as follows:

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

Ultimately, I would like to call only one function that is able to print out the array and return predict_label and prob_estimates.

I am actually calling this function in python via ctypes and my python function is included bellow.

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
Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
Ruven Guna
  • 414
  • 7
  • 25
  • 6
    Returning multiple values is usually acomplished by returning a structure, so you're on the right track. – Some programmer dude Jul 05 '18 at 04:16
  • You are on the right track. Learn how to use structures. – DYZ Jul 05 '18 at 04:16
  • A `struct` describes the area of memory, it is not a variable in itself so cannot hold values. You declare the struct, then create a variable of that struct type, then set each *member* in that struct variable with a value. – cdarke Jul 05 '18 at 04:57
  • By the way, the elements of `x` are `double`, yet `a`, `b`, `c`, `d` are floats. Then in your struct you are using `float` again, then you try to initialise them to `double` values. `5.0` is a `double`, `5.0f` is a float. *Don't mix them* (if in doubt, use `double`). – cdarke Jul 05 '18 at 05:45
  • Possible duplicate of [returning multiple values from a function](https://stackoverflow.com/questions/3829167/returning-multiple-values-from-a-function) – Yunnosch Jul 05 '18 at 05:53
  • Please don't add `**answered**` to the title. SO shows a question is answered already when you accept an answer for your question. Also editing your question and changing the context (float to double) makes the accepted answer look incorrect. I didn't rollback that edit because there was more context added to the question, but keep it in mind for future questions. – Mark Tolonen Jul 06 '18 at 07:22

3 Answers3

3

First you need to define your structure:

struct re_val{
    float predict_label;
    float prob_estimates;
};

And then you need to return a struct re_val from your function:

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

So the full example would be:

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

Try it here: http://rextester.com/WRROW32352

Jerry Jeremiah
  • 9,045
  • 2
  • 23
  • 32
2

This is generally done with structures. To initialise it on the stack, do something like this.

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

See this link Are there any downsides to passing structs by value in C, rather than passing a pointer?; specifically, the prototype could have been static void c_func(const struct sample *const x, struct re_val *const rv); where rv pointer is filled, especially where re_val is a large structure or one wants it to be potentially allocated on the heap.

There are different ways to pass information out of a function, such as,

  • returning on the stack, as here. Usually this is good for structures which the memory imprint is trivial. div, strtod64;
  • passing a pointer to the data that's to be filled. fread, fscanf, snprintf, sprintf, strfmon, strncat, strncpy, strptime, strftime, asctime_r, ctime_r, localtime_r;
  • keeping a static struct -- this method not re-entrant and overwrites the same data multiple times. It is not thread-safe. asctime, ctime, gmtime, localtime, strtok;
  • having a type associated with the state that one needs to pass to do operations, FILE *: fopen/fclose, regex_t: regcomp/regfree, or global, errno: perror;
  • returning an heap-allocated pointer which the user must free. For example, asprintf.
Neil
  • 1,767
  • 2
  • 16
  • 22
1

This answer is an alternative to using structs - which is of course valid - you can return multiple value by reference/via a pointer. And answers the main question whether it is possible to return mulitple value from a single function.

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

The function sum_diff assigns uses the arguments a, b, sum and diff. a and b are input arguments and sum and diff are the output arguments. Notice that the function checks whether sum and diff are not NULL, this allows the caller to optionally get the difference or sum. This might be handy with more computational intensive calculations.

hetepeperfan
  • 4,292
  • 1
  • 29
  • 47
  • Hi, thanks! I have managed to solve this part but I came across some issues when I tried to call the function in python. I have posted a new question as I feel that that should be a different question. Please let me know if you are able to answer the question. This is the link: https://stackoverflow.com/questions/51186226/calling-a-c-function-in-python-and-returning-2-values – Ruven Guna Jul 05 '18 at 08:29