Handmade Network»Forums
Italo
28 posts
Help with stack, heap and inline functions best practices
Edited by Italo on
Suppose I have something like the following:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
my_thing_t thing = {};
thing.a = 23;
thing.b = {5, 0};
thing.c = 25553;
thing.d = 23;
thing.e = 0.23;
thing.f = "abc";
thing.g = 23;
thing.h = 'k';
thing.i = 23;
thing.j = 0;
thing.k = thing.j + 4;
thing.l = {2341};
thing.m = 223;
thing.n = 2343;
do_something_with_thing(program_state, thing);


This functions gets called in about 40 different places ~5 times per second. (with different arguments)

I could pass all those struct members as parameters to the function instead of creating a struct for this, but imagine the struct is much bigger than that. This would make the code mode readable (at least I think so?).
Now, imagine that function is about 50 lines of code. What should I do here?

- Make the function inline and pass `thing` by value
- Make the function inline and pass `thing`'s reference? (probably never good, right?)
- Allocate `thing` on the heap and pass it's reference?
- Pass everything as arguments even though it could be more than 20 arguments?

Is this something I should not do?
Isn't this too much like OOP? (in the sense that I'm basically creating an object and calling its method)

What are better alternatives?
498 posts
Help with stack, heap and inline functions best practices
Edited by ratchetfreak on
The inline keyword says nothing about whether the function will be inlined or not. All it means is that the One Definition Rule doesn't apply to it (it's still UB to have the same inline function twice with differerent definitions though).

The only way to pick is the fastest is to try it and benchmark it. Also investigate the resulting code.

For readability I would suggest to split the struct up in logical parts and pass those.
Mārtiņš Možeiko
2237 posts / 1 project
Help with stack, heap and inline functions best practices
Edited by Mārtiņš Možeiko on
My feeling is that you want to pass this large structure by address (or reference). Although it will not make difference if you are calling only 5 times per second. Even if you pass by value and compiler will need to make a copy every time, it will make no measurable impact on your performance.

Making function inline or not should not be decision you make based on how and what you pass in arguments. As rachetfreak already explained, it should be decision about what and where you declare and define.

And there is absolutely nothing OOP in passing large or small structures to function by value, address or reference.

Jeremiah Goerdt
209 posts / 2 projects
Programmer, Linux apologist, and not-so-wiseman.
Help with stack, heap and inline functions best practices
If you pass a reference, does it need to be on the heap?

Is there a reason *not* to keep it on the stack and pass a reference?
Mārtiņš Možeiko
2237 posts / 1 project
Help with stack, heap and inline functions best practices
Edited by Mārtiņš Možeiko on
No, it doesn't be on the heap.
From compiler point of view it doesn't matter where is variable - on stack, heap or global. All it does it just passes address to argument and address can be anything. Reference is nothing else than fancy C++ a pointer which cannot be NULL, and you cannot change where it points to (not the value of element it points to, but actual address it contains). And because obviously you can have pointers that point to local variables, that means you can also have references that points to local variables;

Here's an example:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// function that prints out integer from pointer, and changes it to 42
void ptr(int* a)
{
  printf("%d\n", *a);
  a = 42;
}

// function that prints out integer from reference, and changes it to 24
void ref(int& a)
{
  printf("%d\n", a);
  a = 24;
}

int global = 111;

int main()
{
  ptr(&global);           // will print 111, and change it to 42
  ref(global);            // will print out 42, and change it to 24
  printf("%d\n", global); // will print out 24

  int local = 999;
  ptr(&local);           // will print 999, and change it to 42
  ref(local);            // will print out 42, and change it to 24
  printf("%d\n", local); // will print out 24

  int& temp_ref = local; // reference that points to local variable
  temp_ref = 1212;       // change "local" variable to 1212
  printf("%d\n", local); // will print out 1212

  int* heap = malloc(sizeof(*heap));
  *heap = 444;
  ptr(heap);             // will print 444, and change it to 42
  ref(*heap);            // will print out 42, and change it to 24
  printf("%d\n", *heap); // will print out 24
}


Jeremiah Goerdt
209 posts / 2 projects
Programmer, Linux apologist, and not-so-wiseman.
Help with stack, heap and inline functions best practices
Sorry, I wasn't very clear. I meant for his use case, does he need to heap allocate instead of just leave his stuff on the stack.
Mārtiņš Možeiko
2237 posts / 1 project
Help with stack, heap and inline functions best practices
No, he doesn't. That's exactly what my example shows. Imagine "my_thing_t thing" instead of "int local" in my example. Function ref will happily accept it.