What does const mean in C?

const is a keyword. More specifically, const is a type qualifier. Type qualifiers are part of C types. In the type int const, const is a type qualifier, and int is a type specifier. Here, const qualifies the type int. Qualifiers change the semantics of the type in some way. Other type qualifiers include volatile and restrict.

(Note you can also write const int, which means the same thing as int const. But should never write this. Always write const in “postfix”, on the right-hand side of the type it is qualifying. That you can write const int is a quirk of the C syntax which should not exist.)

How does int const differ from int? A value of type T const cannot be assigned to, except when initialized. For example:

int main(void)
{
  int i = 3;         // OK
  int const ci = 5;  // OK; assignment at initialization
  i = 7;             // OK
  ci = 9;            // ERROR; assigning to `const` value
  return 0;
}

You cannot assign to a const value, even if assigning the same value:

int main(void)
{
  int const ci = 5;
  ci = 5;            // ERROR, even though same value
  return 0;
}

You cannot assign to a const value, even if it was not initialized at declaration:

int main(void)
{
  int const ci;      // no initializer
  ci = 5;            // ERROR; cannot assign to `const` value even though uninitialized
  return 0;
}

const can sit in more complex types to express ideas like “pointer to an unassignable int”, or “unassignable pointer to an assignable int”, or “an array of unassignable integers”. Some examples:

typedef int const int_const;                      // An unassignable int
typedef int * int_ptr;                            // An assignable pointer to an assignable int
typedef int_const * int_const_ptr;                // An assignable pointer to an unassignable int
typedef int * const int_ptr_const;                // An unassignable pointer to an assignable int
typedef int_const * const int_const_ptr_const;    // An unassignable pointer to an unassignable int

int main(void)
{
  int i = 2;                                      // An assignable int
  int_const j = 3;                                // An unassignable int

  i = j;                                          // OK
  // j = i;                                       // ERROR; cannot assign to const

  int_ptr pointer_to_int;
  pointer_to_int = &i;                            // OK
  // pointer_to_int = &j;                         // ERROR; `int_const` cannot be safely converted to `int`

  int_const_ptr pointer_to_const_int;
  pointer_to_const_int = &i;                      // OK! `int` can be converted to `const int`
  pointer_to_const_int = &j;                      // OK

  int_ptr_const const_pointer_to_int = &i;        // OK
  // int_ptr_const const_pointer_to_int_2 = &j;   // ERROR; `int_const` cannot be converted to `int`

  *const_pointer_to_int = 2;                      // OK, constness of pointer does not affect constness of pointee
  // const_pointer_to_int = &i;                   // ERROR, cannot assign to const pointer

  int_const_ptr_const const_pointer_to_const_int_1 = &i;  // OK! `int` can be converted to `int const`
  int_const_ptr_const const_pointer_to_const_int_2 = &j;  // OK

  return 0;
}

Note in particular that int can be soundly converted to int const. This is perhaps surprising: doesn’t this mean the compiler can make false assumptions? For example, if we tell the compiler that a value is const, might the compiler not cache the value? As far as I understand, this is not the case, because const doesn’t actually mean has a “constant value”. const means “unassignable in this context”. Unassignable is not the same as immutable.

Some examples of const in the standard library:

int atoi(const char * str);  // atoi promises not to assign to the characters in the array

// qsort demands a comparator which does not modify the things it compares
void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*));

(Note that the standard library uses the horrible const char construction. You should read it as char const.)

Tagged #c, #programming, #semantics.
👋 I'm Jim, a full-stack product engineer. Want to build an amazing product and a profitable business? Read more about me or Get in touch!

More by Jim

This page copyright James Fisher 2016. Content is not associated with my employer. Found an error? Edit this page.