Question

Lets imagine that we have function that should return two return values. For instance we have some function that returns char* and its length. Char is allocated within that particular function.

I can imagine following ways of doing that:

int foo(char **result);       // Passing pointer to char*, returning int
char* bar(int *len);          // Passing pointer to int, returning char*
struct char_and_len foobar(); // Returning struct that contains both values

Is there any other ways to implement multiple values and what's the most effective way to do that?

I'd really appreciate detailed explanation, considering performance, memory alignment or any other hidden C feature.

Was it helpful?

Solution

There are two cases here. If you are working in a codebase/framework (e.g. Glib) that has a standard string struct used throughout the entire application, then use your third option:

struct string function();

If your codebase is not using one standard struct everywhere for strings, I would advise against using a struct. The hassle of converting back and forth is not really worth it.

Otherwise, the convention (at least that I've seen) is to return the char* and have the length as a pointer parameter:

char* function(int* length);

OTHER TIPS

Another way:

void foo(char **result, int *len);

The worst in my opinion is:

struct char_and_len foobar();

The one I prefer is the one I showed you, because I don't like to mix return values in both arguments and effective return.

You can just return an array and wrap it in a struct:

typedef struct {
    char *strings[2];
} RetType;

RetType func()
{
    return (RetType){ { "foo", "bar" } };
}

Another idiomatic solution is C to pass an array to your function and have it filled:

void func(char *strings[2])
{
    strings[0] = "foo";
    strings[1] = "bar";
}

A third solution is to return one value and pass the other one by pointer (though this is more meaningful if you have values of distinct types):

char *func(char **outparm)
{
    *outparm = "foo";
    return "bar";
}

Also, excuse me for not being const-correct.

My favourite would be

void foobar(struct char_and_len*);

For the following reasons:

  • Only a single parameter needs to be passed
  • return value / out parameter aren't mixed
  • return values can be ignored, especially when the return value needs to be deallocated again this can be a serious source of programming errors. Out parameters cannot be ignored.
  • Having a pointer to the struct avoids too much copy operations. Only one pointer needs to be provided to the function.
  • This way the caller of the function can decide where the struct char_and_len is stored (on the heap, stack) while when using return values the data needs to be put on the stack at least temporarily

Use a string.

For the specific example you cite, remember that length is implicitly or explicitly a property of any string type. For example, C-style strings are null-terminated, so even though there's not an explicit length the caller can still determine the length of the string. Pascal-style strings include length as the first byte. char* isn't necessarily a string, it might be a plain old text buffer where you do need the length. But the point of string types is to avoid the need to pass data and length separately.

More generally...

A function can only return one value, so if you need to return more than that you need to either package everything up into a single value using a struct, or pass a pointer (or pointers) to a location to receive the results. Which method you use depends on the circumstances. Do you already have a struct defined for the data that needs to be returned? Is the caller likely to have an existing object that could receive the results? There is no best method, only an appropriate method for the situation.

The best way is always work with pointers. In C, every function duplicate the arguments passed in a different zone of memory. The best way is the second one of the three that you have posted in term of performance.

But I would pass as argument a pointer to a struct wich contains both, lenght and string with a void return.

In C it isn't "normal" to return two values. That means that as you already did you could create a struct to return the result. That is the formally correct way of doing it, but not the simplest one and it is coumbersome. So I would totaly forget that solution.

Generically, the other way of returning results is by passing arguments by reference (in Pascal VB etc ). In C there is not the possibility to pass them by reference instead a pointer is passed. But in C++ there is the possibility to pass the variable by reference ( that simply means passing the pointer but using the variable ).

So I believe the simplest way of doing what you need is to define:

char* bar(int *lenP); //

now you have the result of a function that could return two results:

like if it was defined as pseudo syntax (s,l)=bar();

Additionally you could also use:

void bar(char * *s,int * lenP); // that case treats equally the too arguments.

In C++ I would use the by reference approach because while being the same from the practical point of view (what the processor does) it is simpler for the programmer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top