It's remarkably easy to fill the stack up due to infinite recursion;
void func() { func(); }
will do it well enough. Any function call pushes information onto the stack (at least a return address), and so if it doesn't stop calling itself at some point, it'll run out of available stack.
I find it hard to see why you would dislike such a function as you have shown as an example of doing it. It does what is needed and it does it fast.
However, it is possible that optimisation will cause the compiler to turn the function into an infinite loop, as it is easy to spot it doesn't do anything.
If you want a demonstration of a function that actually does something,
int factorial(int n) { return n<= 0 ? 1 : factorial(n - 1) * n; }
is a good example, given a suitably large value of n, and no compiler optimisation (or it might spot the opportunity for tail recursion and turn that into a loop as well).
Failing that, try this (Ackermann's function, an example of a recursive function that is not primitively recursive and is also not going to be subject to optimisation in the last line.
unsigned int A(unsigned int m, unsigned int n)
{
if (m == 0) return n + 1;
if (n == 0) return A(m - 1, 1);
return A(m - 1, A(m, n - 1));
}
Exercise for the reader: Given an intelligent compiler, how much optimisation can be applied to minimise the recursion.