简体   繁体   English

如何从 C 中的函数返回多个值?

[英]How do I return multiple values from a function in C?

If I have a function that produces a result int and a result string , how do I return them both from a function?如果我有一个生成结果int和结果string的函数,我如何从函数中返回它们?

As far as I can tell I can only return one thing, as determined by the type preceding the function name.据我所知,我只能返回一件事,这取决于函数名称前面的类型。

I don't know what your string is, but I'm going to assume that it manages its own memory.我不知道你的string是什么,但我假设它管理自己的内存。

You have two solutions:您有两种解决方案:

1: Return a struct which contains all the types you need. 1:返回一个包含你需要的所有类型的struct

struct Tuple {
    int a;
    string b;
};

struct Tuple getPair() {
    Tuple r = { 1, getString() };
    return r;
}

void foo() {
    struct Tuple t = getPair();
}

2: Use pointers to pass out values. 2:使用指针传递值。

void getPair(int* a, string* b) {
    // Check that these are not pointing to NULL
    assert(a);
    assert(b);
    *a = 1;
    *b = getString();
}

void foo() {
    int a, b;
    getPair(&a, &b);
}

Which one you choose to use depends largely on personal preference as to whatever semantics you like more.您选择使用哪一个很大程度上取决于个人偏好,即您更喜欢哪种语义。

Option 1 : Declare a struct with an int and string and return a struct variable. Option 1 :声明一个带有 int 和 string 的结构体并返回一个结构体变量。

struct foo {    
 int bar1;
 char bar2[MAX];
};

struct foo fun() {
 struct foo fooObj;
 ...
 return fooObj;
}

Option 2 : You can pass one of the two via pointer and make changes to the actual parameter through the pointer and return the other as usual: Option 2 :您可以通过指针传递两者之一,并通过指针更改实际参数并像往常一样返回另一个:

int fun(char **param) {
 int bar;
 ...
 strcpy(*param,"....");
 return bar;
}

or或者

 char* fun(int *param) {
 char *str = /* malloc suitably.*/
 ...
 strcpy(str,"....");
 *param = /* some value */
 return str;
}

Option 3 : Similar to the option 2. You can pass both via pointer and return nothing from the function: Option 3 :与选项 2 类似。您可以通过指针传递两者并且从函数中不返回任何内容:

void fun(char **param1,int *param2) {
 strcpy(*param1,"....");
 *param2 = /* some calculated value */
}

Since one of your result types is a string (and you're using C, not C++), I recommend passing pointers as output parameters.由于您的结果类型之一是字符串(并且您使用的是 C,而不是 C++),我建议将指针作为输出参数传递。 Use:用:

void foo(int *a, char *s, int size);

and call it like this:并这样称呼它:

int a;
char *s = (char *)malloc(100); /* I never know how much to allocate :) */
foo(&a, s, 100);

In general, prefer to do the allocation in the calling function, not inside the function itself, so that you can be as open as possible for different allocation strategies.一般来说,更喜欢在调用函数中进行分配,而不是在函数本身内部,这样你就可以对不同的分配策略尽可能开放。

Create a struct and set two values inside and return the struct variable.创建一个结构体并在其中设置两个值并返回结构体变量。

struct result {
    int a;
    char *string;
}

You have to allocate space for the char * in your program.您必须为程序中的char *分配空间。

Two different approaches:两种不同的方法:

  1. Pass in your return values by pointer, and modify them inside the function.通过指针传递返回值,并在函数内修改它们。 You declare your function as void, but it's returning via the values passed in as pointers.您将函数声明为 void,但它通过作为指针传入的值返回。
  2. Define a struct that aggregates your return values.定义一个聚合返回值的结构。

I think that #1 is a little more obvious about what's going on, although it can get tedious if you have too many return values.我认为 #1 对正在发生的事情更明显一点,尽管如果返回值太多会变得乏味。 In that case, option #2 works fairly well, although there's some mental overhead involved in making specialized structs for this purpose.在这种情况下,选项 #2 工作得相当好,尽管为此目的制作专门的结构会涉及一些心理开销。

Use pointers as your function parameters.使用指针作为函数参数。 Then use them to return multiple value.然后使用它们返回多个值。

One approach is to use macros.一种方法是使用宏。 Place this in a header file multitype.h将其放在头文件multitype.h

#include <stdlib.h>

/* ============================= HELPER MACROS ============================= */

/* __typeof__(V) abbreviation */

#define TOF(V) __typeof__(V)

/* Expand variables list to list of typeof and variable names */

#define TO3(_0,_1,_2,_3) TOF(_0) v0; TOF(_1) v1; TOF(_2) v2; TOF(_3) v3;
#define TO2(_0,_1,_2)    TOF(_0) v0; TOF(_1) v1; TOF(_2) v2;
#define TO1(_0,_1)       TOF(_0) v0; TOF(_1) v1;
#define TO0(_0)          TOF(_0) v0;

#define TO_(_0,_1,_2,_3,TO_MACRO,...) TO_MACRO

#define TO(...) TO_(__VA_ARGS__,TO3,TO2,TO1,TO0)(__VA_ARGS__)

/* Assign to multitype */

#define MTA3(_0,_1,_2,_3) _0 = mtr.v0; _1 = mtr.v1; _2 = mtr.v2; _3 = mtr.v3;
#define MTA2(_0,_1,_2)    _0 = mtr.v0; _1 = mtr.v1; _2 = mtr.v2;
#define MTA1(_0,_1)       _0 = mtr.v0; _1 = mtr.v1;
#define MTA0(_0)          _0 = mtr.v0;

#define MTA_(_0,_1,_2,_3,MTA_MACRO,...) MTA_MACRO

#define MTA(...) MTA_(__VA_ARGS__,MTA3,MTA2,MTA1,MTA0)(__VA_ARGS__)

/* Return multitype if multiple arguments, return normally if only one */

#define MTR1(...) {                                                           \
    typedef struct mtr_s {                                                    \
      TO(__VA_ARGS__)                                                         \
    } mtr_t;                                                                  \
    mtr_t *mtr = malloc(sizeof(mtr_t));                                       \
    *mtr = (mtr_t){__VA_ARGS__};                                              \
    return mtr;                                                               \
  }

#define MTR0(_0) return(_0)

#define MTR_(_0,_1,_2,_3,MTR_MACRO,...) MTR_MACRO

/* ============================== API MACROS =============================== */

/* Declare return type before function */

typedef void* multitype;

#define multitype(...) multitype

/* Assign return values to variables */

#define let(...)                                                              \
  for(int mti = 0; !mti;)                                                     \
    for(multitype mt; mti < 2; mti++)                                         \
      if(mti) {                                                               \
        typedef struct mtr_s {                                                \
          TO(__VA_ARGS__)                                                     \
        } mtr_t;                                                              \
        mtr_t mtr = *(mtr_t*)mt;                                              \
        MTA(__VA_ARGS__)                                                      \
        free(mt);                                                             \
      } else                                                                  \
        mt

/* Return */

#define RETURN(...) MTR_(__VA_ARGS__,MTR1,MTR1,MTR1,MTR0)(__VA_ARGS__)

This makes it possible to return up to four variables from a function and assign them to up to four variables.这使得可以从一个函数返回最多四个变量并将它们分配给最多四个变量。 As an example, you can use them like this:例如,您可以像这样使用它们:

multitype (int,float,double) fun() {
    int a = 55;
    float b = 3.9;
    double c = 24.15;

    RETURN (a,b,c);
}

int main(int argc, char *argv[]) {
    int x;
    float y;
    double z;

    let (x,y,z) = fun();

    printf("(%d, %f, %g\n)", x, y, z);

    return 0;
}

This is what it prints:这是它打印的内容:

(55, 3.9, 24.15)

The solution may not be as portable because it requires C99 or later for variadic macros and for-statement variable declarations.该解决方案可能不是那么可移植,因为它需要 C99 或更高版本的可变参数宏和 for 语句变量声明。 But I think it was interesting enough to post here.但我认为在这里发帖很有趣。 Another issue is that the compiler will not warn you if you assign them the wrong values, so you have to be careful.另一个问题是,如果您为它们分配了错误的值,编译器不会警告您,因此您必须小心。

Additional examples, and a stack-based version of the code using unions, are available at my github repository .其他示例以及使用联合的基于堆栈的代码版本可在我的github 存储库中找到

By passing parameters by reference to function.通过引用函数传递参数。

Examples:例子:

 void incInt(int *y)
 {
     (*y)++;  // Increase the value of 'x', in main, by one.
 }

Also by using global variables but it is not recommended.也可以使用全局变量,但不推荐使用。

Example:例子:

int a=0;

void main(void)
{
    //Anything you want to code.
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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