views:

785

answers:

11

Important: Please see this very much related question: Return multiple values in C++.

I'm after how to do the same thing in ANSI C? Would you use a struct or pass the addresses of the params in the function? I'm after extremely efficient (fast) code (time and space), even at the cost of readability.

EDIT: Thanks for all the answers. Ok, I think I owe some explanation: I'm writing this book about a certain subset of algorithms for a particular domain. I have set myself the quite arbitrary goal of making the most efficient (time and space) implementations for all my algos to put up on the web, at the cost of readability and other stuff. That is in part the nature of my (general) question.

Answer: I hope I get this straight, from (possibly) fastest to more common-sensical (all of this a priori, i.e. without testing):

  1. Store outvalues in global object (I would assume something like outvals[2]?), or
  2. Pass outvalues as params in the function (foo(int in, int *out1, int *out2)), or
  3. return a struct with both outvals, or
  4. (3) only if the values are semantically related.

Does this make sense? If so, I think Jason's response is the closest, even though they all provide some piece of the "puzzle". Robert's is fine, but at this time semantics is not what I'm after (although his advice is duly noted)

Thank you all.

+2  A: 

You have described the two possible solutions and your perceived performance constraint. Where you go from here is really up to you - we don't have enough information to make an informed judgement.

anon
I understand. Just starting C and wanted to know whether there was a better way. Would you say structs are more expensive than the alternative?
Dervin Thunk
To editors - please be sure of your own spelling when making corrections.
anon
@Dervin There probably is not an enormous difference in performance between the two options, but this will be dependent on how you use the struct etc. which we have no details of. If performance is that important (and frankly, it rarely is) then yo must perform your own measurements to find out which is fastest.
anon
Dervin, if you just started C performance should be the least of your concern. Learn to write maintainable code first.
GMan
GMan, thanks for the textbook advice, but at this stage in my career, I can assure you I can worry about both at the same time. :)
Dervin Thunk
+1  A: 

The fastest Q&D way that I can think of is to pass the values on a global object, this way you skip the stack operation just keep in mind that it won't be thread safe.

Shay Erlichmen
Not necessarily, if the global objects needs to be fetched into the cache.
quant_dev
A: 

I would pass the address to a struct. If the information to be returned isn't complex, then just passing in the addresses to the values would work too.

Personally, it really comes down to how messy the interface would be.

void SomeFunction( ReturnStruct* myReturnVals )
{
  // Fill in the values
}   

// Do some stuff    
ReturnStruct returnVals;
SomeFunction( &returnVals);    
// Do more stuff
Soo Wei Tan
Excuse my ignorance, I don't know much C yet. Why is returning a local copy of the struct bad?
Mike Cooper
Acutally, it wouldn't be bad, provided you're not pointing to memory allocated within the function. I'm just going to remove that block to reduce confusion.
Soo Wei Tan
@Soo Wei Tan - no, you were correct about memory allocated within the function (and this being bad) - you didn't need to remove it, it's about training to do the right way.
KevinDTimm
I'm glad he removed it. There's nothing bad with returning a struct from a function in C. It in fact caused confusion.
Johannes Schaub - litb
+6  A: 

Both ways are valid, certianly, but I would would consider the semantics (struct vs parameter reference) to decide which way best communicates you intentions to the programmer.

If the values you are returning are tightly coupled, then it is okay to return them as a structure. But, if you are simply creating artificial mechanism to return values together (as a struct), then you should use a parameter reference (i.e. pass the address of the variables) to return the values back to the calling function.

Enjoy,

Robert C. Cartaino

Robert Cartaino
+3  A: 

As Neil says, you need to judge it for yourself.

To avoid the cost of passing anything, use a global. Next best is a single structure passed by pointer/reference. After that are individual pointer/reference params.

However, if you have to pack data into the structure and then read it back out after the call, you may be better off passing individual parameters.

If you're not sure, just write a bit of quick test code using both approaches, execute each a few hundred thousand times, and time them to see which is best.

Jason Williams
+3  A: 

Easiest to read should be passed addresses in the function, and it should be fast also, pops and pushes are cheap:

void somefunction (int inval1, int inval2, int *outval1, int *outval2) {
   int x = inval1;
   int y = inval2;
// do some processing
   *outval1 = x;
   *outval2 = y;
   return;
}
KevinDTimm
Dervin Thunk
no. I wrote exactly what I meant.
KevinDTimm
it is ok, but please highlight your code
mtasic
A: 

This depends massively on your architecture, and also if you expect (or can have) the function inlined. I'd first write the code in the simplest way, and then worry about speed if that shows up as an expensive part of your code.

Dave Rigby
+1  A: 

I think that when you return a struct pointer, you probably need to manually find some memory for that. Addresses in parameter list are allocated on the stack, which is way faster.

Tadeusz A. Kadłubowski
A: 

In either case, you're passing references, so performance should be similar. If there is a chance that the function never actually returns a value, you could avoid the cost of the malloc with the "return a struct" option since you'd simply return null.

My personal preference is to return a dynamically allocated (malloc'd) struct. I avoid using function arguments for output because I think it makes code more confusing and less maintainable in the long-term.

Cory Engebretson
Dynamically allocated means memory leak potential at the very least. That means that users of your function have to be much more careful.
Jonathan Leffler
+1  A: 

Keep in mind that sometimes is faster to pass parameters by value and update on return (or make local copies on the stack) than by reference... This is very evident with small structures or few parameters and lots of accesses.

fortran
A: 

Returning a local copy of the structure is bad because if the struct was declared as non-static inside the function, it becomes null and void once you exit the function.

And to all the folks suggesting references, well the OP did say "C," and C doesn't have them (references).

And sweet feathery Jesus, can I wake up tomorrow and not have to see anything about the King of Flop on TV?

xcramps