Function parameters
When you use a function in C/C++ [or most other programming languages] you are likely to pass it some parameters – data which may be processed by the function or give it information on what action is required. For the majority of programmers, outside of the world of embedded software, parameters are just a fact – no real issues. They are likely to be quite uninterested in how parameters are passed and how efficient and secure that process that might be. Embedded developers tend to want details. Efficient code is essential and avoiding possible bugs is always desirable. So, maybe a look at how parameter passing actually works might be useful …
When embedded systems were all programmed in assembly language, the programmer had complete freedom with parameter passing and a number of options were available:
- Use global variables – not generally recommended, but might be most efficient in some circumstances.
- Use registers – this can be fast and efficient; the required data might already be in a register [which is almost the same as using a global variable, so it needs care].
- Use the stack – SP-relative addressing may be efficient in many processors; this approach leads to reentrant code.
- Use a dedicated memory block – this approach may make sense, if the addressing modes of the processor are limited, but probably results in non-reentrant code.
In C, some aspects of parameter passing are specified by the language definition; others are implementation dependent and may vary from one compiler to another. There are no specific constraints on the parameter passing mechanism. It is left to the compiler writer to choose between stack [which is most common], registers or something else. It is bad programming practice to make assumptions about how parameters are passed. You could write code like this:
void fun(int n)
{
int *p, x;
p = &n;
x = *++p;
This function simply takes the address of the first parameter, assumes that it is on the stack and indexes off of that address to find further parameters. Please do not do this.
In C/C++ parameters are normally passed by value – the value passed as a parameter is copied into the formal parameter of the function. C++ gives the option of passing by reference, which means that a called function can access variables which are passed as parameters by the calling function. To achieve this in C, you need to use pointers [which is, of course, what C++ is doing behind the scenes].
A small quiz to test your knowledge of C parameter passing: when, in C, is parameter passing by reference the default? Please comment or email. Sorry no prizes, just fame and glory.
Comments
Leave a Reply
You must be logged in to post a comment.
As per the specification ISO/IEC 9899::201x WG14/N1336 document, parameter passing must be handled as
An argument may be an expression of any object type. In preparing for the call to a function, the arguments are evaluated, and each parameter is assigned the value of the corresponding argument.
A function may change the values of its parameters, but these changes cannot affect the values of the arguments. On the other hand, it is possible to pass a pointer to an object, and the function may change the value of the object pointed to. A parameter declared to have array or function type is adjusted to have a pointer type.
So, by default we cannot label parameter passing either as “by-value” or “by-reference” as it depends on the type of parameter.
Moreover, for aggregate data types, architectural limitations can force the parameter to actually be passed-as-reference but rather treated as passed-by-value by having a copy.
Very comprehensive answer Ganesh!
The key example is the passing of an array. Many programmers forget that an array name, with no “[]” operators applied, is just a (constant) pointer to the start of the array. So, passing an array is intrinsically passing a pointer – i.e. passing by reference.
Similarly, using the name of a function causes its address to be passed. However, this bare-name-equals-address convention is general, not a peculiarity of parameter-passing. Technically, in C, *all* arguments are passed by value; in these cases the value happens to be the address of something and the parameter declaration, whatever form it takes, is the declaration of a pointer which can hold that value.
In C++, though, we can actually declare parameters to be references to objects, so semantically we can pass-by-reference (although it’s really a pointer being used underneath).
You are quite correct Peter, of course. My point is that passing an array this way looks very like passing by reference, even though you are, in fact, simply passing a pointer by value.