returning multiple values in C 
Author Message
 returning multiple values in C

So far I have come across three ways of returning multiple values
from a C function.

i.      using pointers.
        int     foo(int *bar)
        {
                *bar = 2;
                return  1;
        }

        a = foo(&b);

ii.     using global variables
        int     bar;
        int     foo()
        {
                bar = 2;
                return 1;
        }

        a = foo();
        b = bar;

iii.    using structures
        struct {
                int     foo;
                int     bar;    
        } val_struct;

        struct  val_struct foo()
        {
                struct  val_struct r;
                r.foo = 2;
                r.bar = 1;
                return r;
        }

        struct  val_struct      x;
        x = foo();
        a = x.foo;
        b = x.bar;

I don't really have that much experience in C, so I would appreaciate
some pointers on which approach to use as well as their pros and cons.

Thanks!

Hasdi



Sun, 26 Jul 1998 03:00:00 GMT  
 returning multiple values in C


Quote:
>So far I have come across three ways of returning multiple values
>from a C function.
>i.  using pointers.
>    int     foo(int *bar)
>    {
>            *bar = 2;
>            return  1;
>    }
>    a = foo(&b);
>ii. using global variables
>    int     bar;
>    int     foo()
>    {
>            bar = 2;
>            return 1;
>    }

>    a = foo();
>    b = bar;
>iii.        using structures
>    struct {
>            int     foo;
>            int     bar;    
>    } val_struct;
>    struct  val_struct foo()
>    {
>            struct  val_struct r;
>            r.foo = 2;
>            r.bar = 1;
>            return r;
>    }
>    struct  val_struct      x;
>    x = foo();
>    a = x.foo;
>    b = x.bar;
>I don't really have that much experience in C, so I would appreaciate
>some pointers on which approach to use as well as their pros and cons.

The problem is not unique to C; I know of NO language which does even
a fair job of this.

This should have been addressed on day 2 of producing languages.

There is one other way in C; the use of &.  The standard frexp function
is called as y = frexp(x, &n).  This should be of the form

        (y, n) = frexp(x):

but that is not legal.  Both y and n are outputs, but while y can
end up in a register, if it is wanted to have n in a register, it
will have to be loaded.  This applies to ALL of the methods indicated
so far.

There is a way in fortran 90 to do this more generally, but it still
has the same drawback.  In a subroutine, INTENT can be used to declare
if an argument is the address of input, output, or both.

--
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907-1399



Sun, 26 Jul 1998 03:00:00 GMT  
 returning multiple values in C

Quote:

> So far I have come across three ways of returning multiple values
> from a C function.

> i.      using pointers.
>         int     foo(int *bar)
>         {
>                 *bar = 2;
>                 return  1;
>         }

>         a = foo(&b);

This is the one most commonly used, but it's a little clumsy...

Quote:
> ii.     using global variables
>         int     bar;
>         int     foo()
>         {
>                 bar = 2;
>                 return 1;
>         }

>         a = foo();
>         b = bar;

This is even worse. Consider what happens if you have a multithreaded program where two
threads call the function at almost the same time. Which instance one will yield the proper
value in the global variable?

Quote:
> iii.    using structures
>         struct {
>                 int     foo;
>                 int     bar;
>         } val_struct;

>         struct  val_struct foo()
>         {
>                 struct  val_struct r;
>                 r.foo = 2;
>                 r.bar = 1;
>                 return r;
>         }

>         struct  val_struct      x;
>         x = foo();
>         a = x.foo;
>         b = x.bar;

This is also quite dangerous. When foo() returns, the space allocated for r in the stack is
freed. Consider this calling sequence:

        x = foo();
        if (x.foo == 2) {
                struct val_struct       y;
                y.foo = x.foo + 2;
                y.bar = x.bar + 2;
        }

where y is also declared to be a stack variable. One approach would be to declare r inside
foo() as static struct, so that it gets actually allocated in global data and not in stack.

Quote:
> I don't really have that much experience in C, so I would appreaciate
> some pointers on which approach to use as well as their pros and cons.

However, I would prefer this kind of an approach over the others:

        int     foo(struct val_struct *p)
        {
                p->foo = 2;
                p->bar = 1;
                return 1;       /* all went okay */
        }

        struct val_struct       x;

        if (foo(&x) == 1) {
                /* All went fine. Now we have the values at x.foo and x.bar */
        }

Quote:
> Thanks!

You're welcome.
 AriL
--
All my opinions are mine and mine alone.


Mon, 27 Jul 1998 03:00:00 GMT  
 returning multiple values in C

<snip>
   > iii.    using structures
   >         struct {
   >                 int     foo;
   >                 int     bar;
   >         } val_struct;
   >
   >         struct  val_struct foo()
   >         {
   >                 struct  val_struct r;
   >                 r.foo = 2;
   >                 r.bar = 1;
   >                 return r;
   >         }
   >
   >         struct  val_struct      x;
   >         x = foo();
   >         a = x.foo;
   >         b = x.bar;
   >

   This is also quite dangerous. When foo() returns, the space
allocated for r in the stack is  
   freed. Consider this calling sequence:

Irrelevant. return is by value, so it is actually a copy of r that is
being passed back. `return &r;' has the problem you mention, `return
r;' is safe.

Cheers
Tanmoy
--

Tanmoy Bhattacharya O:T-8(MS B285)LANL,NM87545 H:#9,3000,Trinity Drive,NM87544
Others see <gopher://yaleinfo.yale.edu:7700/00/Internet-People/internet-mail>,
<http://alpha.acast.nova.edu/cgi-bin/inmgq.pl>or<ftp://csd4.csd.uwm.edu/pub/
internetwork-mail-guide>. -- <http://nqcd.lanl.gov/people/tanmoy/tanmoy.html>
fax: 1 (505) 665 3003   voice: 1 (505) 665 4733    [ Home: 1 (505) 662 5596 ]



Tue, 28 Jul 1998 03:00:00 GMT  
 returning multiple values in C

Quote:
> > ii.     using global variables
> >         int     bar;
> >         int     foo()
> >         {
> >                 bar = 2;
> >                 return 1;
> >         }

> >         a = foo();
> >         b = bar;

> This is even worse.  Consider what happens if you have a multithreaded
> program where two threads call the function at almost the same time.

There is no such thing in ANSI C.  Certainly there are real-life
environments where reentrancy is an issue, but if we're going to talk
about them in this newsgroup, let's be clear that such semantics are
significantly different from those that the C standard defines.

Quote:
> > iii.    using structures
> >     ...
> >         struct  val_struct foo()
> >         {
> >                 struct  val_struct r;
> >                 r.foo = 2;
> >                 r.bar = 1;
> >                 return r;
> >         }

> >         struct  val_struct      x;
> >         x = foo();
> >         a = x.foo;
> >         b = x.bar;

> This is also quite dangerous.

Wrong.

Quote:
> When foo() returns, the space allocated for r in the stack is freed.

Right, but the operation is required to work anyway.  If the function
had been declared as

                struct  val_struct *foo()
and ended with
                return &r;

THEN it would be seriously wrong, for the reason described.  But in the
actual code, the effect is as if a temporary variable of type struct
val_struct was created, r was copied into this temporary, and it was
in turn copied into x.

Quote:
>    int     foo(struct val_struct *p)
>    {
>            p->foo = 2;
>            p->bar = 1;
>            return 1;       /* all went okay */
>    }

This is also safe.

As for which of these choices is the best, there is no good answer.
I would make the choice based on issues such as how the variables
are used elsewhere in the program.  If there is only one bar and it's
naturally global, I'll probably use that approach (unless reentrancy
matters).  If I'm likely to want to continue passing foo and bar around
together as a unit, then I'll probably use the struct.  And if neither
consideration applies, or if this function is one of several that take
different arguments but all return a value like foo, then I'll probably
take option i and pass a pointer to bar as an argument.
--
Mark Brader             |  "It's simply a matter of style, and while there

SoftQuad Inc., Toronto  |   one right style."      -- Ray Butterworth

My text in this article is in the public domain.



Tue, 28 Jul 1998 03:00:00 GMT  
 returning multiple values in C

Quote:

>> iii.    using structures
>>         struct  val_struct foo()
>>         {
>>                 struct  val_struct r;
>>                 r.foo = 2;
>>                 r.bar = 1;
>>                 return r;
>>         }

>>         struct  val_struct      x;
>>         x = foo();
>>         a = x.foo;
>>         b = x.bar;

>This is also quite dangerous. When foo() returns, the space allocated for r in the stack is
>freed.

You mean like:

double sqr(double x) {
    double y=x*x;
    return y;

Quote:
}

This code will fail because y is a local variable which is destroyed
on function return?

I don't think so. Arguments in C are passed/returned by value, not by
reference (including structs).

Chris



Tue, 28 Jul 1998 03:00:00 GMT  
 returning multiple values in C
: > iii.    using structures
: >         struct {
: >                 int     foo;
: >                 int     bar;
: >         } val_struct;
: >
: >         struct  val_struct foo()
: >         {
: >                 struct  val_struct r;
: >                 r.foo = 2;
: >                 r.bar = 1;
: >                 return r;
: >         }
: >
: >         struct  val_struct      x;
: >         x = foo();
: >         a = x.foo;
: >         b = x.bar;
: >

: This is also quite dangerous. When foo() returns, the space allocated for r in the stack is
: freed.

What?!! I read somewhere that in x86 implementation, C only needs to return a pointer to the
structure. I assumed that the compiler would make arrangement so that the data on the stack
will not get overwritten. Oh well, I guess I may be wrong.

: However, I would prefer this kind of an approach over the others:

:       int     foo(struct val_struct *p)
:       {
:               p->foo = 2;
:               p->bar = 1;
:               return 1;       /* all went okay */
:       }

Still ugly, but this is method I usually go for because you don't have to copy the contents
of r to the left side of the equation. :)

See ya

Hasdi



Tue, 28 Jul 1998 03:00:00 GMT  
 returning multiple values in C

|>
|> So far I have come across three ways of returning multiple values
|> from a C function.
|>
|> i.      using pointers.

|This is the one most commonly used, but it's a little clumsy...

Everything is at least a little clumsy.  There could be nice notations
for this concept, but C doesn't have them.

|> ii.     using global variables

|This is even worse. Consider what happens if you have a multithreaded program where two
|threads call the function at almost the same time. Which instance one will yield the proper
|value in the global variable?

It's not just multiple threads that are a concern.  Who is in charge
of a global variable is difficult to track in any moderately large
software project.  Since the parameters that are affected don't appear
in the call, you need to look at the code of each called routine to
determine it's effect on the global state.  

You could discipline yourself to reserve special global variables for
*each* function to use as parameters (shades of the old BASIC!), but
then you still can't call a function recursively, unless you save the
entire state of relevant global variables in local variables before
the call and save the result of the call in local variables before
restoring the state after the call.

|> iii.    using structures
|>         struct {
|>                 int     foo;
|>                 int     bar;
|>         } val_struct;
|>
|>         struct  val_struct foo()
|>         {
|>                 struct  val_struct r;
|>                 r.foo = 2;
|>                 r.bar = 1;
|>                 return r;
|>         }
|>
|>         struct  val_struct      x;
|>         x = foo();
|>         a = x.foo;
|>         b = x.bar;
|>

|This is also quite dangerous. When foo() returns, the space allocated for r in the stack is
|freed. Consider this calling sequence:

Not a problem here.  A *copy* of the structure r is being returned,
not a pointer to it.

|       x = foo();

Here, x is a struct, not a struct pointer, and it is assigned the
value of the call to foo().

|       if (x.foo == 2) {
|               struct val_struct       y;
|               y.foo = x.foo + 2;
|               y.bar = x.bar + 2;
|       }

|where y is also declared to be a stack variable. One approach would be to declare r inside
|foo() as static struct, so that it gets actually allocated in global data and not in stack.

Right, if you intend to return a *pointer* to r.

On the other hand, returning a pointer to a static area has some of the
disadvantages of global variables.  In particular, the next call to
the routine would wipe out the previous result.  If you need to preserve
the previous result, then you still need to make a copy of the object
whose address is returned.

|> I don't really have that much experience in C, so I would appreaciate
|> some pointers on which approach to use as well as their pros and cons.
|>

|However, I would prefer this kind of an approach over the others:

|       int     foo(struct val_struct *p)
|       {
|               p->foo = 2;
|               p->bar = 1;
|               return 1;       /* all went okay */
|       }

|       struct val_struct       x;

|       if (foo(&x) == 1) {
|               /* All went fine. Now we have the values at x.foo and x.bar */
|       }

This is really just an example of version i, except that the results
to be returned are collected into a struct for convenience.

The main advantage to version i (over passing back a pointer, at
least) is that the caller has complete control over the memory used to
receive the results.  If you get back a pointer to memory that you
don't own, how do you know if it's a static region (which needs to be
saved before the next call) or a dynamic region (which you are now
responsible for freeing)?  A disadvantage is that the caller needs
to know how big a region to pass.

Of the three versions presented here, I'd say that global variables
are by far the inferior choice.  Choosing between the others is really
mostly a matter of taste.

The ANSI C library actually contains examples of all four methods:
pointer-passing, struct-returning (see div()), global variable setting
(see errno), and pointer-returning (see fopen()).
--
                Matthew Saltzman
                Clemson University Math Sciences



Tue, 28 Jul 1998 03:00:00 GMT  
 returning multiple values in C

:> iii.    using structures
:>         struct {
:>                 int     foo;
:>                 int     bar;
:>         } val_struct;
:>
:>         struct  val_struct foo()
:>         {
:>                 struct  val_struct r;
:>                 r.foo = 2;
:>                 r.bar = 1;
:>                 return r;
:>         }
:>
:>         struct  val_struct      x;
:>         x = foo();
:>         a = x.foo;
:>         b = x.bar;
:>

:This is also quite dangerous. When foo() returns, the space allocated for r in the stack is
:freed. Consider this calling sequence:

:       x = foo();
:       if (x.foo == 2) {
:               struct val_struct       y;
:               y.foo = x.foo + 2;
:               y.bar = x.bar + 2;
:       }

:where y is also declared to be a stack variable. One approach would be to declare r inside
:foo() as static struct, so that it gets actually allocated in global data and not in stack.

Since "r" is returned, this is _not_ an issue. Maybe you thought
about returning a pointer to a struct from a function.

If you return an "int" from a function, you usually don't declare
the variable that holds the return value "static", do you?

Another question is if it is efficient to return a struct from
a function.

Kurt
--
| Kurt Watzka                             Phone : +49-89-2180-6254




Tue, 28 Jul 1998 03:00:00 GMT  
 returning multiple values in C

: > iii.    using structures
: >         struct {
: >                 int     foo;
: >                 int     bar;
: >         } val_struct;
: >
: >         struct  val_struct foo()
: >         {
: >                 struct  val_struct r;
: >                 r.foo = 2;
: >                 r.bar = 1;
: >                 return r;
: >         }
: >
: >         struct  val_struct      x;
: >         x = foo();
: >         a = x.foo;
: >         b = x.bar;
: >

: This is also quite dangerous. When foo() returns, the space allocated for r in the stack is
: freed.

Not quite.

Any C compiler must ensure that the function's return value is correctly
returned to the caller.  It's the same as if foo returned an integer; the only
difference is the type of thing being returned.  If foo were written like
this:

int foo(void)
{
    int r;
    r = 2;
    return r;

Quote:
}

the space allocated for r in the stack is still freed when foo returns.  But
no C programmer I know would consider this dangerous.

There is a more insidious problem with this technique, though.  One
implementation that I've seen sets aside a global structure (this is done
invisibly to the programmer, by the compiler), and the value of r is copied
into that global structure before foo's stack frame is destroyed.  This is
fine for a single-threaded program, but it causes problems in a multithreaded
environment, or one where foo could be called by interrupt routines.

--
Mark C. Orton
employed by (but not speaking for)
Pulse Communications, Inc.



Wed, 29 Jul 1998 03:00:00 GMT  
 returning multiple values in C

: :where y is also declared to be a stack variable. One approach would be to declare r inside
: :foo() as static struct, so that it gets actually allocated in global data and not in stack.

: Since "r" is returned, this is _not_ an issue. Maybe you thought
: about returning a pointer to a struct from a function.

: If you return an "int" from a function, you usually don't declare
: the variable that holds the return value "static", do you?

: Another question is if it is efficient to return a struct from
: a function.

Frankly, I prefer the technique posted by Mr Lukumies...

typedef foo_struct foo;

int manipulate_foo(foo *);      instead of
foo manipulate_foo();

since in most implementation, the compiler end up compiling
this....
        foo manipulate_foo(),bar;
        bar = manipulate_foo();

into something like this...
        foo *manipulate_foo(),bar;
        bar = *(manipulate_foo())

but just a little safer. :/ I don't see a reason to make an
extra copy in the function and then perform a copy operation
after the function returns. Then again, there are tradeoffs I
neglect to mention.

I find the struct returning approach to be a nuisance sometimes.
Consider the ldiv function.

ldiv_t ldiv(long numer, long denom)

Which returns two values, quot and rem. To actually use this,
you need to have a variable of type ldiv_t. so...

long    a,b,d,e;
ldiv_t  c;
...
c = ldiv(a,b);
d = c.quot;
e = c.rem;
...

A good compiler will optimize c out of existence. I just wished
that I could do something perl can already do...

(d,e) = ldiv(a,b);

less typing and looks cleaner. This will probably led to better
coding options for the compiler.

I wonder if there is a C-variant that can do this sort of thing.

Cheers,

Hasdi



Wed, 29 Jul 1998 03:00:00 GMT  
 returning multiple values in C

     >
     > So far I have come across three ways of returning multiple values
     > from a C function.

     > i.      using pointers.
     >         int     foo(int *bar)

     > ii.     using global variables
     >         int     bar;
     >         int     foo()

     > iii.    using structures
     >         struct {
     >                 int     foo;
     >                 int     bar;
     >         } val_struct;
     >
     >         struct  val_struct foo()
     >         {
     >                 struct  val_struct r;
     >                 r.foo = 2;
     >                 r.bar = 1;
     >                 return r;
     >         }
     >
     >         struct  val_struct      x;
     >         x = foo();
     >         a = x.foo;
     >         b = x.bar;
     >

     This is also quite dangerous. When foo() returns, the space allocated
     for r in the stack is freed.

     --
     All my opinions are mine and mine alone.

Did anyone else pick this one up? The standard clearly says the values
of the struct are transfered in this case. The fact that r in the
function goes out of scope on the return is irrelevant. If the
programmer returned a pointer to the struct then yes, there would be a
problem. The example above is both correct and safe. The mechanism for
multiple return used does affect usage, and yes globals are frowned
upon under most circumstances, on the other hand the standard supports
it for `errno'! Similarly a container object is commonly passed as a
pointer for modification by the function. If this is not the intent,
then the const type modifier should be used. The mechanism used to
return more than one variable from a function should reflect the
reason the function is modifying the variable, and how those variables
will be used as a result.

--
Douglas

---
=============================================================================

                                        Fax: +44 131-667 7209
============================= Mostly harmless ===============================



Wed, 29 Jul 1998 03:00:00 GMT  
 returning multiple values in C

: So far I have come across three ways of returning multiple values
: from a C function.
:
: i.    using pointers.
:       int     foo(int *bar)
:       {
:               *bar = 2;
:               return  1;
:       }
:
:       a = foo(&b);
:

To me, this is the typical method when a and b are not related.  I find
it not aesthetic because the caller uses "b=..." and the called uses
"*b=..." to assign to the same variable.

: ii.   using global variables
:       int     bar;
:       int     foo()
:       {
:               bar = 2;
:               return 1;
:       }
:
:       a = foo();
:       b = bar;
:

Globals are kind of like goto's.  They have their place but are abused
and some people avoid them at all costs.  I tend to use them in places
where multiple tasks need to communicate, such as a main program and
an interrupt service routine, or a foreground and background task.

: iii.  using structures
:       struct {
:               int     foo;
:               int     bar;    
:       } val_struct;
:      
:       struct  val_struct foo()
:       {
:               struct  val_struct r;
:               r.foo = 2;
:               r.bar = 1;
:               return r;
:       }
:
:       struct  val_struct      x;
:       x = foo();
:       a = x.foo;
:       b = x.bar;
:

This makes sense when a and b are naturally related and get passed around
together a lot.  Streams I/O uses it.

In your method, foo writes values to a temporary struct r, and the return
copies them to the destination struct x.

Alternatively, you can pass a pointer to x to foo, and let foo write to
x directly.  This might be faster if you need to return many values.

--



Wed, 29 Jul 1998 03:00:00 GMT  
 returning multiple values in C


: > So far I have come across three ways of returning multiple values
: > from a C function.

: > iii.    using structures
: >         struct {
: >                 int     foo;
: >                 int     bar;
: >         } val_struct;
: >
: >         struct  val_struct foo()
: >         {
: >                 struct  val_struct r;
: >                 r.foo = 2;
: >                 r.bar = 1;
: >                 return r;
: >         }
: >
: >         struct  val_struct      x;
: >         x = foo();
: >         a = x.foo;
: >         b = x.bar;
: >
:
: This is also quite dangerous. When foo() returns, the space allocated for r in the stack is
: freed.

So.  That's the compiler's problem, not yours.  Most implementations I
know of will pass a hiden first parameter, with the target address, and
copy the results in there.  A really good implementation would remark
that in this case, it can cram all of the results into a register, and
return them that way.  Whatever the implementation does, it's not your
problem.
--

GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils, tudes et ralisations en logiciel orient objet --
              -- A la recherche d'une activit dans une region francophone



Wed, 29 Jul 1998 03:00:00 GMT  
 returning multiple values in C


Quote:


>: :where y is also declared to be a stack variable. One approach would be to declare r inside
>: :foo() as static struct, so that it gets actually allocated in global data and not in stack.

                        ....................

Quote:
>I find the struct returning approach to be a nuisance sometimes.
>Consider the ldiv function.
>ldiv_t ldiv(long numer, long denom)
>Which returns two values, quot and rem. To actually use this,
>you need to have a variable of type ldiv_t. so...
>long        a,b,d,e;
>ldiv_t      c;
>...
>c = ldiv(a,b);
>d = c.quot;
>e = c.rem;
>...
>A good compiler will optimize c out of existence. I just wished
>that I could do something perl can already do...

How can the compiler optimize it out of existence?  Functions
do not return results that way; the only possible way to avoid
storing the ldiv struct is to store it elsewhere, say on the
stack.  But a good compiler will not store the return value
of a function on a stack, but put it where it is wanted, often
in a register.

I have seen implementations of C which will put vectors and
worse on stacks; this is rarely optimal.  

Quote:
>(d,e) = ldiv(a,b);
>less typing and looks cleaner. This will probably led to better
>coding options for the compiler.
>I wonder if there is a C-variant that can do this sort of thing.

Not really.  This is something which should have been put into
programming languages almost from day 1.  Most early computers
had the above as hardware.
--
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907-1399



Thu, 30 Jul 1998 03:00:00 GMT  
 
 [ 29 post ]  Go to page: [1] [2]

 Relevant Pages 

1. Multiple-value function returns

2. return multiple values

3. Returning Multiple Values From Function

4. How about: Multiple value return in C

5. Can the return statement use multiple values?

6. Multiple .cs files in assembly

7. Simple C++ question: Using return values (by value)

8. Newbie: separate big .cs file into small .cs files

9. One return vs multiple returns

10. Returning error values vs. not returning

11. ATL Server: POSTing multiple values

12. Sorting multiple values at once.

 

 
Powered by phpBB® Forum Software