DEV Community

loading...

Type qualifier: register, volatile and restrict - C Programming

Bo
Coder, Learner
・3 min read

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:

#include <stdio.h>

int main() {
    register int i = 0;
    int* p = &i;
    printf("address of i: %p\n", p);
    return 0;
}
Enter fullscreen mode Exit fullscreen mode

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;
      |     ^~~
Enter fullscreen mode Exit fullscreen mode

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

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:

char * strcpy(char * restrict s1, const char * restrict s2);
Enter fullscreen mode Exit fullscreen mode

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

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

int main() {
    char s[50] = "hello world";
    strcpy(s, s);
    puts(s);
    return 0;
}
Enter fullscreen mode Exit fullscreen mode

We pass s as the same s1 and s2 parameter. Use gcc to compile it:

$ gcc main.c -o main
Enter fullscreen mode Exit fullscreen mode

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.

$ gcc main.c -Wrestrict -o main
Enter fullscreen mode Exit fullscreen mode

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);
      |  
Enter fullscreen mode Exit fullscreen mode

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:

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

int main() {
    char s[50] = "hello world";
    char* d = s;
    strcpy(d, s);
    puts(s);
    return 0;
}
Enter fullscreen mode Exit fullscreen mode

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
  • The gcc command used in this post is "gcc (Ubuntu 9.2.1-9ubuntu2) 9.2.1 20191008"

Discussion (0)