Nearby lessons

113 of 124

C - register Storage Class

register asks the compiler to keep a variable in a CPU register instead of memory. Learn what registers are, the one rule the keyword actually enforces, and why modern optimisers made it obsolete.

What a Register Is

In simple words: a register is a tiny storage slot inside the CPU itself. Reading one takes a fraction of a nanosecond; reading main memory can take a hundred times longer. A processor has only a handful — perhaps 16 general-purpose ones — so they are precious.
StorageTypical access timeCapacity
CPU registerUnder 1 cycle~16 slots
L1 cache~4 cyclesTens of KB
L2 / L3 cache~12–40 cyclesMB
Main memory (RAM)~200 cyclesGB
Example01
CCode Cell
1#include <stdio.h>
2 
3int main()
4{
5 register int fast = 10; /* please keep this in a register */
6 int normal = 20; /* the compiler decides freely */
7 
8 printf("fast = %d\n", fast);
9 printf("normal = %d\n", normal);
10 printf("\nBoth behave identically in your program.\n");
11 return 0;
12}
Output
fast   = 10
normal = 20

Both behave identically in your program.

It Is Only a Hint

The compiler is free to ignore register entirely, and modern ones almost always do — they run their own register allocator:

Example02
CCode Cell
1#include <stdio.h>
2 
3int main()
4{
5 /* Asking for far more registers than the CPU has.
6 The compiler simply puts the extras in memory. */
7 register int a = 1, b = 2, c = 3, d = 4, e = 5;
8 register int f = 6, g = 7, h = 8, i = 9, j = 10;
9 register int k = 11, l = 12, m = 13, n = 14, o = 15;
10 register int p = 16, q = 17, r = 18, s = 19, t = 20;
11 
12 printf("Sum = %d\n", a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p+q+r+s+t);
13 printf("No error - the compiler ignored what it could not honour.\n");
14 return 0;
15}
Output
Sum = 210
No error - the compiler ignored what it could not honour.

The One Rule That Is Enforced

You cannot take the address of a register variable. This is not a hint — it is a hard compile error, because a register has no memory address to take. It is the only observable effect the keyword reliably has, and it is what makes register useless for arrays: you can never index one without an address.
Example03
CCode Cell
1#include <stdio.h>
2 
3int main()
4{
5 register int r = 10;
6 int normal = 20;
7 
8 /* int *p = &r; ERROR: address of register variable requested */
9 int *p = &normal; /* fine */
10 
11 printf("r = %d\n", r);
12 printf("*p = %d\n", *p);
13 printf("sizeof r = %zu (sizeof is still allowed)\n", sizeof(r));
14 
15 /* register int arr[5];
16 Legal to declare, but arr[0] needs &arr[0] - so unusable. */
17 return 0;
18}
Output
r        = 10
*p       = 20
sizeof r = 4  (sizeof is still allowed)

Where It Can Be Used

register applies only to local variables and function parameters — never to globals or static variables, which by definition live in memory:

Example04
CCode Cell
1#include <stdio.h>
2 
3/* register int global = 10; ERROR: file-scope declaration
4 specifies 'register' */
5 
6int sum(register int n) /* legal on a parameter */
7{
8 register int total = 0; /* legal on a local */
9 register int i;
10 
11 for (i = 1; i <= n; i++) total += i;
12 return total;
13}
14 
15int main()
16{
17 /* register static int bad; ERROR: two storage classes */
18 
19 printf("sum(1..100) = %d\n", sum(100));
20 return 0;
21}
Output
sum(1..100) = 5050

The Historical Use Case

In the 1970s and 80s compilers did little optimisation, so hinting the hot loop counter genuinely helped. This is the pattern you will see in old code:

Example05
CCode Cell
1#include <stdio.h>
2 
3/* How it was written in 1985 */
4long sumOldStyle(register int n)
5{
6 register long total = 0;
7 register int i;
8 
9 for (i = 1; i <= n; i++)
10 total += i;
11 return total;
12}
13 
14/* How it is written today - the optimiser handles it */
15long sumModern(int n)
16{
17 long total = 0;
18 for (int i = 1; i <= n; i++)
19 total += i;
20 return total;
21}
22 
23int main()
24{
25 printf("Old style : %ld\n", sumOldStyle(1000));
26 printf("Modern : %ld\n", sumModern(1000));
27 printf("\nIdentical machine code from any modern compiler with -O2.\n");
28 return 0;
29}
Output
Old style : 500500
Modern    : 500500

Identical machine code from any modern compiler with -O2.

Why Compilers Outperform the Hint

Register allocation is a global optimisation problem. The compiler sees the whole function; you see one declaration:

The compiler knowsYou are guessing
How often each variable is actually usedWhich one feels hottest
Exact live ranges, so registers can be reusedThat the variable exists
The real register count of the target CPURoughly 16, maybe
Which values must spill and whenNothing
How inlining changes the pictureNothing
Example06
CCode Cell
1#include <stdio.h>
2 
3int main()
4{
5 int a = 1, b = 2, c = 3;
6 int result;
7 
8 /* The optimiser sees that 'a' dies after this line and can reuse
9 its register for 'c'. A 'register' hint cannot express that. */
10 result = a + b;
11 result = result * c;
12 
13 printf("result = %d\n", result);
14 printf("\nRegister allocation needs whole-function analysis.\n");
15 return 0;
16}
Output
result = 9

Register allocation needs whole-function analysis.

register vs the Other Storage Classes

It behaves exactly like auto apart from the address restriction:

registerautostatic
Stored inRegister (if honoured)StackData segment
LifetimeThe blockThe blockWhole program
Default valueGarbageGarbageZero
& allowedNoYesYes
Valid at file scopeNoNoYes
Example07
CCode Cell
1#include <stdio.h>
2 
3void compare(void)
4{
5 register int r = 0;
6 auto int a = 0;
7 static int s = 0;
8 
9 r++; a++; s++;
10 printf("register=%d auto=%d static=%d\n", r, a, s);
11}
12 
13int main()
14{
15 compare();
16 compare();
17 compare();
18 return 0;
19}
Output
register=1 auto=1 static=1
register=1 auto=1 static=2
register=1 auto=1 static=3

How to Actually Make Code Faster

If you reach for register because a loop is slow, these are the things that will genuinely help:

Example08
CCode Cell
1#include <stdio.h>
2 
3int main()
4{
5 int data[8] = {5, 3, 8, 1, 9, 2, 7, 4};
6 int i, total = 0;
7 
8 /* 1. Turn on the optimiser: gcc -O2 program.c
9 2. Measure before you change anything
10 3. Pick a better algorithm - O(n log n) beats any register hint
11 4. Access memory sequentially so the cache can predict you
12 5. Hoist work out of the loop yourself */
13 
14 for (i = 0; i < 8; i++) /* sequential: cache-friendly */
15 total += data[i];
16 
17 printf("total = %d\n", total);
18 printf("\n-O2 does more for this loop than any keyword.\n");
19 return 0;
20}
Output
total = 39

-O2 does more for this loop than any keyword.

Its Status Today

Still valid C, still useless in practice. C++17 removed it as a storage class entirely:

LanguageStatus
C89 – C23Valid, but ignored as a hint by every mainstream compiler
C++98 – C++14Valid, deprecated in C++11
C++17 and laterRemoved — the keyword is reserved but unusable
Trainer's Note: learn register to read old code and to answer the interview question, not to write it. It is the clearest example in C of an optimisation that made sense for the hardware and compilers of its era and stopped making sense once optimisers got good.

Common Mistakes

  • Taking the address&registerVar is a hard compile error.
  • Expecting a guarantee — it is a hint the compiler may ignore.
  • Using it at file scope — only locals and parameters are allowed.
  • Combining it with static — a variable cannot have two storage classes.
  • Declaring a register array — indexing needs an address, so it is unusable.
  • Expecting a speed-up — measure; you will find none.
  • Sprinkling it everywhere — the extras are silently ignored and the code just reads worse.
📝 Key Takeaways
  • register requests storage in a CPU register — the compiler may refuse.
  • You cannot take the address of a register variable; that rule IS enforced.
  • Only usable on local variables and function parameters.
  • Modern optimisers allocate registers better than any human hint.
  • It is deprecated in C++17 and effectively obsolete in C.

🧠 Test Your Knowledge

4 Questions
Progress: 0 / 4