Wenn ich eine Funktion habe, die ein Ergebnis int
und ein Ergebnis string
erzeugt, wie gebe ich beide von einer Funktion zurück?
Soweit ich das beurteilen kann, kann ich nur eines zurückgeben, was durch den Typ vor dem Funktionsnamen bestimmt wird.
Ich weiß nicht, was Ihr string
ist, aber ich gehe davon aus, dass es sein eigenes Gedächtnis verwaltet.
Sie haben zwei Lösungen:
1: Gib ein struct
zurück, das alle benötigten Typen enthält.
struct Tuple {
int a;
string b;
};
struct Tuple getPair() {
Tuple r = { 1, getString() };
return r;
}
void foo() {
struct Tuple t = getPair();
}
2: Verwenden Sie Zeiger, um Werte zu verteilen.
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);
}
Welches Sie wählen, hängt weitgehend von Ihren persönlichen Vorlieben ab, welche Semantik Sie bevorzugen.
Option 1
: Deklarieren Sie eine Struktur mit einem int und einem string und geben Sie eine Strukturvariable zurück.
struct foo {
int bar1;
char bar2[MAX];
};
struct foo fun() {
struct foo fooObj;
...
return fooObj;
}
Option 2
: Sie können einen der beiden über einen Zeiger übergeben und den aktuellen Parameter über den Zeiger ändern und den anderen wie gewohnt zurückgeben:
int fun(char **param) {
int bar;
...
strcpy(*param,"....");
return bar;
}
oder
char* fun(int *param) {
char *str = /* malloc suitably.*/
...
strcpy(str,"....");
*param = /* some value */
return str;
}
Option 3
: Ähnlich wie bei Option 2. Sie können sowohl per Zeiger übergeben als auch nichts von der Funktion zurückgeben:
void fun(char **param1,int *param2) {
strcpy(*param1,"....");
*param2 = /* some calculated value */
}
Zwei verschiedene Ansätze:
Ich denke, dass # 1 etwas offensichtlicher ist, was los ist, obwohl es langweilig werden kann, wenn Sie zu viele Rückgabewerte haben. In diesem Fall funktioniert Option 2 recht gut, obwohl die Erstellung spezieller Strukturen für diesen Zweck mit einem gewissen Aufwand verbunden ist.
Da einer Ihrer Ergebnistypen ein String ist (und Sie C und nicht C++ verwenden), empfehle ich die Übergabe von Zeigern als Ausgabeparameter. Verwenden:
void foo(int *a, char *s, int size);
und nenne es so:
int a;
char *s = (char *)malloc(100); /* I never know how much to allocate :) */
foo(&a, s, 100);
Im Allgemeinen bevorzugen Sie die Zuweisung in der Funktion aufrufend, nicht in der Funktion selbst, damit Sie für verschiedene Zuweisungsstrategien so offen wie möglich sind.
Erstellen Sie eine Struktur, setzen Sie zwei Werte und geben Sie die Strukturvariable zurück.
struct result {
int a;
char *string;
}
Sie müssen Platz für das char *
in Ihrem Programm.
Verwenden Sie Zeiger als Funktionsparameter. Verwenden Sie sie dann, um mehrere Werte zurückzugeben.
Durch Übergabe von Parametern anhand der Funktion.
Beispiele:
void incInt(int *y)
{
(*y)++; // Increase the value of 'x', in main, by one.
}
Auch bei Verwendung globaler Variablen wird dies jedoch nicht empfohlen.
Beispiel:
int a=0;
void main(void)
{
//Anything you want to code.
}
Ein Ansatz ist die Verwendung von Makros. Platziere dies in einer Header-Datei 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__)
Auf diese Weise können bis zu vier Variablen aus einer Funktion zurückgegeben und bis zu vier Variablen zugewiesen werden. Als Beispiel können Sie sie wie folgt verwenden:
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;
}
Dies ist, was es druckt:
(55, 3.9, 24.15)
Die Lösung ist möglicherweise nicht so portabel, da für variadische Makros und for-statement-Variablendeklarationen C99 oder höher erforderlich ist. Aber ich denke, es war interessant genug, um hier zu posten. Ein weiteres Problem ist, dass der Compiler Sie nicht warnt, wenn Sie ihnen die falschen Werte zuweisen. Sie müssen also vorsichtig sein.
Weitere Beispiele und eine stapelbasierte Version des Codes, der Gewerkschaften verwendet, finden Sie in meinem Github-Repository .