Choosing function parameter types - pointers or objects?

B

ballpointpenthief

At the moment, I only write functions which accept pointers as
arguments in order to change a value, but I've realised it would often
be a lot more effiecient to pass a pointer rather than an actual
object.
I know this question is a bit vague, but I was wondering about any
rules / guidelines / style issues, for when to use pointers, and when
not to, in your function parameters?

I'm also interested in any grey areas, or even off-topic functions that
have been written like in the win32 API for instance, but I doubt
anyone else is.

Cheers, Matt
 
R

Richard Heathfield

ballpointpenthief said:
I know this question is a bit vague, but I was wondering about any
rules / guidelines / style issues, for when to use pointers, and when
not to, in your function parameters?

If it's a native type (int, short, long, double, that sort of thing), pass
it in raw unless you need to hack its value. Anything else - structs and
stuff - pass a pointer.
 
F

Frederick Gotham

ballpointpenthief posted:

I know this question is a bit vague, but I was wondering about any
rules / guidelines / style issues, for when to use pointers, and when
not to, in your function parameters?


You'd have the measure the efficiency of:

(1) Passing the object by value (thus copying it in the process).

and

(2) Passing its address, and dereferencing the address.


For the intrinsic types, (1) is faster.

For a huge type, an object of which is perhaps a kilobyte, (2) would be
faster.


I'm sure the others can give you a more detailed reply.
 
K

Keith Thompson

Richard Heathfield said:
ballpointpenthief said:

If it's a native type (int, short, long, double, that sort of thing), pass
it in raw unless you need to hack its value. Anything else - structs and
stuff - pass a pointer.

I wouldn't hesitate to pass a *small* structure directly.
 
G

goose

Frederick Gotham wrote:

You'd have the measure the efficiency of:

(1) Passing the object by value (thus copying it in the process).

and

All function arguments are passed by value in C.
(2) Passing its address, and dereferencing the address.


For the intrinsic types, (1) is faster.

For a huge type, an object of which is perhaps a kilobyte, (2) would be
faster.

Although the OP never mentioned efficiency[1], I think a good strategy
to pass as little as possible would be to pass a pointer whenever
sizeof (datatype) > sizeof (void *).

Efficiency on such a microscopic scale is a silly goal anyway, the
savings are not going to offset the disadvantages. The general rule
I use is to use opaque data types whenever I can which solves the
whole problem quite neatly. In the rare occasion that I cannot use
an opaque type, I'd still use pointers for any data that contains more
than one primitive type (structs, arrays) and only pass the value
itself when it is a primitive type.

goose,
hand

[1] I got the impression the question was more one of style than
of efficiency, but thats just me :).
 
S

Stephen Sprunk

ballpointpenthief said:
At the moment, I only write functions which accept pointers as
arguments in order to change a value, but I've realised it would often
be a lot more effiecient to pass a pointer rather than an actual
object.
I know this question is a bit vague, but I was wondering about any
rules / guidelines / style issues, for when to use pointers, and when
not to, in your function parameters?

It is common practice to pass read-only parameters of primitive types by
value, and everything else by pointer.

S
 
F

Frederick Gotham

goose posted:

Although the OP never mentioned efficiency[1], I think a good strategy
to pass as little as possible would be to pass a pointer whenever
sizeof (datatype) > sizeof (void *).


Then there's no discussion, because both methods solve the problem.

One of them is more efficient in certain cases, yes, but both get the job
done.

If the OP doesn't care about efficiency, the just flip a coin.
 
I

Ian Collins

goose said:
Frederick Gotham wrote:

You'd have the measure the efficiency of:

(1) Passing the object by value (thus copying it in the process).

and


All function arguments are passed by value in C.

(2) Passing its address, and dereferencing the address.


For the intrinsic types, (1) is faster.

For a huge type, an object of which is perhaps a kilobyte, (2) would be
faster.


Although the OP never mentioned efficiency[1], I think a good strategy
to pass as little as possible would be to pass a pointer whenever
sizeof (datatype) > sizeof (void *).
Unfortunately this is platform specific.

The cut-off point between pass by value and by pointer varies form
system to system. sizeof(void*) is a reasonable general case.
 
J

Joe Wright

Keith said:
I wouldn't hesitate to pass a *small* structure directly.
Why pass a struct rather than a pointer to it? You can examine the
struct either way but if you would modify any member of it, and pass the
struct by value, the function must 'return' the value and you must
assign it to the original struct. If you pass a pointer to it, you can
modify the member of the original struct (in)directly.
 
J

Joe Wright

Richard said:
Keith Thompson said:


I would. Small structures have a habit of growing larger. :)
Agreed. I never pass struct by value, always by address (&). I do accept
struct tm by value from localtime() to populate my local struct tm when
I'm playing with time stuff.
 
I

Ian Collins

Joe said:
Why pass a struct rather than a pointer to it? You can examine the
struct either way but if you would modify any member of it, and pass the
struct by value, the function must 'return' the value and you must
assign it to the original struct. If you pass a pointer to it, you can
modify the member of the original struct (in)directly.
What about a case with a small struct like this:

#include <stdio.h>

typedef struct {
int x;
int y;
} Coord;

Which would you prefer:

Coord addp( const Coord* a, const Coord* b )
{
Coord result;
result.x = a->x+b->x;
result.y = a->y+b->y;
return result;
}

void printp( const Coord* c )
{
printf( "%d,%d" , c->x, c->y );
}

Or

Coord add( Coord a, Coord b )
{
Coord result;
result.x = a.x+b.x;
result.y = a.y+b.y;
return result;
}

void print( Coord c )
{
printf( "%d,%d" , c.x, c.y );
}
 
K

Keith Thompson

Joe Wright said:
Why pass a struct rather than a pointer to it? You can examine the
struct either way but if you would modify any member of it, and pass
the struct by value, the function must 'return' the value and you must
assign it to the original struct. If you pass a pointer to it, you can
modify the member of the original struct (in)directly.

If I want to modify it, of course I can pass a pointer to it (or I can
return the new value as the function's result). The same applies to
scalars.

If I *don't* want to modify it, I can either pass a
pointer-to-const-whatever, or I can pass the structure itself directly
(by value).

For example, if I have a structure for complex numbers (assuming I'm
not using C99's _Complex), it makes sense to treat that structure as
if it were a scalar.

If I'm going to think about performance, it's likely (but by no means
certain) that the overhead of accessing the parameter inside the
function indirectly through a pointer could exceed the savings of
passing a (small) pointer vs. a (slightly larger) structure. The
difference either way isn't likely to be significant as long as the
structure is, and is likely to remain, fairly small.

If performance isn't likly to be significant, I'll do what seems most
natural. For a small structure, especially one that represents
something vaguely number-like, passing it directly rather than via a
pointer seems like the most natural thing to do.
 
R

Richard Heathfield

Joe Wright said:

I do accept
struct tm by value from localtime() to populate my local struct tm when
I'm playing with time stuff.

Well, you actually get a /pointer/ back from localtime(). As far as I can
tell, though, localtime() is not allowed to fail, so it's okay to deref it
as in:

struct tm lt = *localtime(&tt);
 
N

Nelu

Richard Heathfield said:
Joe Wright said:



Well, you actually get a /pointer/ back from localtime(). As far as I can
tell, though, localtime() is not allowed to fail, so it's okay to deref it
as in:

struct tm lt = *localtime(&tt);

Why isn't localtime() allowed to fail?
 
R

Richard Heathfield

Nelu said:
Why isn't localtime() allowed to fail?

Because the Standard doesn't say it can.

Note that gmtime() /is/ allowed to fail - it can return a null pointer if
Greenwich Mean Time has decided to take the week off. But localtime() is
given no such licence. Therefore, it *must* succeed.

Since I live only about 50 miles from the Greenwich Meridian, I find this to
be adequate to my needs. :)
 
N

Nelu

Richard Heathfield said:
Nelu said:
[snip]
Why isn't localtime() allowed to fail?

Because the Standard doesn't say it can.

Note that gmtime() /is/ allowed to fail - it can return a null pointer if
Greenwich Mean Time has decided to take the week off. But localtime() is
given no such licence. Therefore, it *must* succeed.

Since I live only about 50 miles from the Greenwich Meridian, I find this to
be adequate to my needs. :)

7.23.3.4 The localtime function
...
Returns
3 The localtime function returns a pointer to the broken-down time, or
a null pointer if the specified time cannot be converted to local time.

Doesn't this mean that it can fail?
 
K

Keith Thompson

Nelu said:
Richard Heathfield said:
Nelu said:
[snip]
Why isn't localtime() allowed to fail?

Because the Standard doesn't say it can.

Note that gmtime() /is/ allowed to fail - it can return a null pointer if
Greenwich Mean Time has decided to take the week off. But localtime() is
given no such licence. Therefore, it *must* succeed.

Since I live only about 50 miles from the Greenwich Meridian, I
find this to be adequate to my needs. :)

7.23.3.4 The localtime function
...
Returns
3 The localtime function returns a pointer to the broken-down time, or
a null pointer if the specified time cannot be converted to local time.

Doesn't this mean that it can fail?

Yes. The C90 standard doesn't have that wording; it just says:

The localtime function converts the calendar time pointed to by
timer into a broken-down time, expressed as local time.

It seems to me that was a flaw in the C90 standard, corrected in C99.
 
R

Richard Heathfield

Keith Thompson said:
Nelu <[email protected]> writes:

Yes. The C90 standard doesn't have that wording; it just says:

The localtime function converts the calendar time pointed to by
timer into a broken-down time, expressed as local time.

It seems to me that was a flaw in the C90 standard, corrected in C99.

Ah, I hadn't checked the C99 Standard, so I didn't realise it had been
changed. Well, that's Yet Another Reason to stick with C90, I'm afraid. I
like the idea of a localtime function that is guaranteed by international
agreement to be infallible (whether they meant to guarantee that or not).
 
R

Richard Bos

Keith Thompson said:
I wouldn't hesitate to pass a *small* structure directly.

I wouldn't hesitate to pass even a large structure directly. I expect
the optimiser to DTRT.

Richard
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,181
Messages
2,570,970
Members
47,537
Latest member
BellCorone

Latest Threads

Top