About the order of input parameters

7.3k views Asked by At

For a function/method contains many input parameters, does it make a difference if passing-in in different orders? If does, in what aspects (readability, efficiency, ...)? I am more curious about how should I do for my own functions/methods?

It seems to me that:

  1. Parameters passing by references/pointers often come before parameters passing by values. For example:

    void* memset( void* dest, int ch, std::size_t count ); 
    
  2. Destination parameters often come before source parameters. For example:

    void* memcpy( void* dest, const void* src, std::size_t count );
    
  3. Except for some hard constraints, i.e., parameters with default values must come last. For example:

    size_type find( const basic_string& str, size_type pos = 0 ) const;
    
  4. They are functional equivalent (achieve the same goal) no matter what order they pass in.

4

There are 4 answers

0
Tony Delroy On BEST ANSWER

There are a few reasons it can matter - listed below. The C++ Standard itself doesn't mandate any particular behaviours in this space, so there's no portable way to reason about performance impact, and even if something's demonstrably (slightly) faster in one executable, a change anywhere in the program, or to the compiler options or version, might remove or even reverse the earlier benefit. In practice it's extremely rare to hear people talk about parameter ordering being of any significance in their performance tuning. If you really care you'd best examine your own compiler's output and/or benchmark resultant code.

Exceptions

The order of evaluation of expressions passed to function parameters is unspecified, and it's quite possible that it could be affected by changes to the order they appear in the source code, with some combinations working better in the CPU execution pipeline, or raising an exception earlier that short-circuits some other parameter preparation. This could be a significant performance factor if some of the parameters are temporary objects (e.g. results of expressions) that are expensive to allocate/construct and destruct/deallocate. Again, any change to the program could remove or reverse a benefit or penalty observed earlier, so if you care about this you should create a named temporary for parameters you want evaluated first before making the function call.

Registers vs cache (stack memory)

Some parameters may be passed in registers, while others are pushed on to the stack - which effectively means entering at least the fastest of the CPU caches, and implies their handling may be slower.

If the function ends up accessing all the parameters anyway, and the choice is between putting parameter X in a register and Y on the stack or vice versa, it doesn't matter much how they're passed, but given the function may have conditions affecting which variables are actually used (if statements, switches, loops that may or may not be entered, early returns or breaks etc.), it's potentially faster if a variable that's not actually needed was on the stack while one that was needed was in a register.

See http://en.wikipedia.org/wiki/X86_calling_conventions for some background and information on calling conventions.

Alignment and padding

Performance could theoretically be affected by the minutae of parameter passing conventions: the parameters may need particular alignment for any - or perhaps just full-speed - access on the stack, and the compiler might choose to pad rather than reorder the values it pushes - it's hard to imagine that being significant unless the data for parameters was on the scale of cache page sizes

Non-performance factors

Some of the other factors you mention can be quite important - for example, I tend to put any non-const pointers and references first, and name the function load_xxx, so I have a consistent expectation of which parameters may be modified and which order to pass them. There's no particularly dominant convention though.

0
Sean On

Strictly speaking it doesn't matter - parameters are pushed onto the stack and the function accessing them by taking them from the stack in some way.

Howver, most C/C++ compilers allow you to specify alternative calling conventions. For example, Visual C++ supports the __fastcall convention which stores the first 2 parameters in the ECX and EDX registers, which (in theory) should give you a performance improvement in the right circumstances.

There's also __thiscall which stores the this pointer in the ECX register. If you're doing C++ then this may be useful.

8
bolov On

There are some answers here mentioning calling conventions. They have nothing to do with your question: No matter what calling convention you use, the order in which you declare the parameters doesn't matter. It doesn't matter which parameters are passed by registers and which are passed by stack, as long as the same number of parameters are passed by registers and the same amount of parameters are passed by stack. Please note that parameters that are higher in size than the native architecture size (4-bytes for 32-bit and 8-byte for 64-bit) are passed by an address, so they are passed with the same speed as a smaller size data.

Let's take an example:

You have a function with 6 parameters. And you have a calling convention, lets call it CA, that passes one parameter by register and the rest (5 in this case) by stack, and a second calling convention, lets call it CB, that passes 4 parameters by registers and the rest (in this case 2) by stack.

Now, of course that CA will be faster than CB, but it has nothing to do with the order the parameters are declared. For CA, it will be as fast no matter which parameter you declare first (by register) and which you declare 2nd, 3rd..6th (stack), and for CB it will be as fast no matter which 4 arguments you declare for registers and which you declare as last 2 parameters.


Now, regarding your question:

The only rule that is mandatory is that optional parameters must be declared last. No non-optional parameter can follow an optional parameter.

Other than that, you can use whatever order you want, and the only strong advice I can give you is be consistent. Choose a model and stick to it.

Some guidelines you could consider:

  • destination comes before source. This is to be close to destination = source.
  • the size of the buffer comes after the buffer: f(char * s, unsigned size)
  • input parameters first, output parameters last (this conflicts with the first one I gave you)

But there is no "wrong" or "right" or even a universal accepted guideline for the order of the parameters. Choose something and be consistent.

Edit

I thought of a "wrong" way to order you parameters: by alphabetic order :).

Edit 2

For example, both for CA, if I pass a vector(100) and a int, it will be better if vector(100) comes first, i.e. use registers to load larger data type. Right?

No. As I have mentioned it doesn't matter the data size. Let's talk on a 32-bit architecture (the same discussion is valid for any architecture 16-bit, 64-bit etc). Let's analyze the 3 case we can have regarding the size of the parameters in relation with the native size of the architecture.

  • Same size: 4-bytes parameters. Nothing to talk here.
  • Smaller size: a 4-bytes register will be used or 4-bytes will be allocated on stack. So nothing interesting here either.
  • Larger size: (e.g. a struct with many fields, or a static array). No matter which method is chosen for passing this argument, this data resides in memory, and what is passed is a pointer (size 4-bytes) to that data. Again we have a 4-bytes register or 4-bytes on the stack.

It doesn't matter the size of the parameters.

Edit 3

How @TonyD explained, the order matters if you don't access all the parameters. See his answer.

0
Chang On

I have somehow found a few related pages.

https://softwareengineering.stackexchange.com/questions/101346/what-is-best-practice-on-ordering-parameters-in-a-function

https://google.github.io/styleguide/cppguide.html#Function_Parameter_Ordering

So first Google's C++ style does not really answer the question since it fails to answer the actual order within the input parameters or output parameters.

The other page basically suggests that order parameters in a sense easy to be understood and used.

For the sake of readability, I personally prefer to order parameter based on alphabet order. But you can also work on some strategy to name the parameters to be nicely ordered so that they could be still easy to be understood and used.