Better to pass struct, or pointer to struct?

502 views Asked by At

I have a data struct, that will be read in a function.

I want the smallest memory, code size, and speed footprint possible. I'm working on AVR.

typedef struct {
    uint16_t clu;
    uint16_t num;
    uint32_t cur_rel;
} FSAVEPOS;

Now, a function that stores file position into the struct:

// Approach 1
FSAVEPOS save_pos(const FFILE* file); // return value

// Approach 2
void save_pos(const FFILE* file, FSAVEPOS* pos); // modify reference

And a function that reverses this (FFILE object is modified):

// Approach 1
void restore_pos(FFILE* file, const FSAVEPOS pos); // pass by value

// Approach 2
void restore_pos(FFILE* file, const FSAVEPOS* pos); // pass by reference

What would you advise as the best idea?

2

There are 2 answers

0
Mabus On

In the first case, when you return a struct in C, it's usually returned in a register if it fits or is implicitly passed by reference and modified AFAIK. So, in the best case it's better and in the worst case is equal than the second approach.

In the second case it depends on the size of a pointer and the size of the struct among other things. In this case is very difficult to say anything without measurement. It probably won't be much different with a struct of that size, though.

However you should consider also having consistency with the rest of your API, and having a system to notify errors if you can't do the operation (if the operation can fail).

4
Peter On

If you are trying to minimise memory footprint, then a struct type that is significantly larger than a pointer is better passed using a pointer. Data that is significantly smaller is better passed by value. If a pointer and the data are about the same size, it doesn't matter much.

Assuming you are on AVR32, your pointer will be 32-bit and the struct is 64-bit (plus any padding).

That would suggest you are better passing by pointer/reference. However, the struct is not particularly large, other considerations may dominate - there is not really a lot in it for your struct type, as it is not particularly large. You would need to measure relevant quantities (memory usage, code size, speed, etc) to be sure.

So the best idea, I suggest, is to measure - these things are affected by host architecture, compiler settings, quality of implementation of the compiler, etc.

Although you haven't asked, larger types (like uint32_t) tend to have larger alignment requirements than smaller types (like uint16_t). A consequence of this is a fairly common guideline of ordering members of your struct so larger types appear first in memory. This is probably not significant in your case either (it is a fair bet that a 16 bit type will be aligned to 16 bit boundaries, and 32-bit types to 32-bit boundaries, so it is likely there will be no padding in your case). However, if you had three uint16_t members rather than two, you would be better off ordering things so the uint32_t members are first. In other words, instead of

typedef struct
{
    uint16_t a,b,c;
    uint32_t d;
} SOME_TYPE;

you would be better off using a different order.

typedef struct
{
    uint32_t d;
    uint16_t a,b,c;
} SOME_TYPE;