I know that in modern compilers with optimizations, declaring a variable as register is merely a suggestion, and the compiler may ignore it, placing the variable in RAM instead of an actual register.
You don't need to do that at all on any semi-modern compiler (from the late 1990s somewhere).
Very old compilers on the other hand (1980s) were plain dumb and would likely just allocate every declared variable on the stack unless you explicitly told it otherwise with the register keyword, which is pretty much obsolete today. It would perhaps only use registers for temporary storage in the middle of a calculation.
But if we assume that we are dealing with a compiler which at least will make some half-hearted attempt of optimizing the code... Then it is important to realize that the place where a variable is declared in C is not necessarily the point in time when that variable gets allocated.
Most compilers would at least be smart enough to know which registers that are occupied internally. And at the point when a value in a register is no longer of any use, the compiler would internally flag that one as available. It will only use stack allocation when it runs out of registers.
And so if the compiler only register allocates variables just before using them, it reduces the need to involve the stack. Even if you declared 100 variables you aren't using all of them simultaneously.
So the amount of registers used at a given time will be restricted to the amount of data the compiler needs to juggle simultaneously at that point. This is why you can write quite efficient C even for small dysfunctional cores like 8 bit MCUs where the amount of registers are severely limited - they are basically 1980s technology.
One exception to all of the above is the ABI calling convention. When data is passed to/from functions, then the compiler must fall in line pre-allocate certain types of variables according to the ABI. Unless the compiler is able to inline the function entirely, which wasn't likely at all even in the 1990s. The reason why the inline keyword was added to C99 was because compilers did such a poor job at automatic inlining. Today this keyword too is mostly obsolete.
registerhas always been "merely a suggestion" from the moment it was introduced.registerdoes is forbidding taking the address of the variable.-O0, the first few objects in a function declared withregisterstorage class will be assigned registers, which may allow code generation that's as good (or on rare occasions) better than what the compiler would produce at higher optimization settings.