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

前端 未结 8 1001
深忆病人
深忆病人 2020-11-22 15:14

If I have a function that produces a result int and a result string, how do I return them both from a function?

As far as I can tell I can

8条回答
  •  情歌与酒
    2020-11-22 15:42

    One approach is to use macros. Place this in a header file multitype.h

    #include 
    
    /* ============================= 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. 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.

提交回复
热议问题