Type qualifier: register, volatile and restrict - C Programming
Tags: clang
Published: 2020-04-25 02:51:18

Type qualifier can be used in front of variables to give compiler some hints about the our using purpose of the variable which can help it to generate better code.

## register

Example: `register int index`

This will give the compiler a hint that the variable `index` will be used heavily and be accessed frequently, it is better to keep it in the machine's register. But remember this is just a hint to compiler, it is not guaranteed this variable will be kept in the register.

Also, since it might be kept in the register, we cannot use the address operator in front of the variable.

Example:

```c
#include <stdio.h>

int main() {
    register int i = 0;
    int* p = &i;
    printf("address of i: %p\n", p);
    return 0;
}
```
Use `gcc` to compile it, we will get the compilation error:
```
register.c: In function ‘main’:
register.c:5:5: error: address of register variable ‘i’ requested
    5 |     int* p = &i;
      |     ^~~
```

## volatile

Example: `volatile char* p`

The `volatile` qualifier will prevent the compiler from optimizing some redundant assignments to a variable. Sometimes compiler will do some optimization to change your code's order or ignore some lines, but those might affect your code logic, especially when you interact with some hardware.

Here is a good example on [stackoverflow](https://stackoverflow.com/questions/246127/why-is-volatile-needed-in-c)

## restrict

Example: `char* restrict s` (notice here, unlike `register` and `volatile` are put in front of the type, we put `restrict` after the type)

The `restrict` qualifier is telling compiler that the pointer it decorated is the ONLY reference to the value it points to in its scope.

We can see an example, the `strcpy` function in C's standard library string.h:

```c
char * strcpy(char * restrict s1, const char * restrict s2);
```

Which tell the compiler that `s1` and `s2` should point to different places. If we have code like this:

```c
#include <stdio.h>
#include <string.h>

int main() {
    char s[50] = "hello world";
    strcpy(s, s);
    puts(s);
    return 0;
}
```
We pass `s` as the same `s1` and `s2` parameter. Use `gcc` to compile it:
```bash
$ gcc main.c -o main
```

Nothing happened, the compiler doesn't even give us a warning. The secret is we need to give the compiler an extra option `-Wrestrict` to let it report this kind problem.

```bash
$ gcc main.c -Wrestrict -o main
```
We will get the warning info:
```
memcpy.c: In function ‘main’:
memcpy.c:6:12: warning: passing argument 1 to restrict-qualified parameter aliases with argument 2 [-Wrestrict]
    6 |     strcpy(s, s);
      |  
```

But again remember, we are just giving compiler a hint, whether the compiler use or ignore it, it is up to the compiler or how smart the compiler is. For example, if we change the code to:

```c
#include <stdio.h>
#include <string.h>

int main() {
    char s[50] = "hello world";
    char* d = s;
    strcpy(d, s);
    puts(s);
    return 0;
}
```
In this code, although `d` and `s` point to the same address, if we use `gcc` to compile it again, although we still use `-Wrestrict` flag, it won't give us any warning info. 


## Reference
* "Programming in C" - Stephen G. Kochan
* [gcc warning options](https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html)
* The `gcc` command used in this post is "gcc (Ubuntu 9.2.1-9ubuntu2) 9.2.1 20191008"