summaryrefslogtreecommitdiff
path: root/content/projects/C_const.md
blob: 9fe86ef4cb46750b3af5b1a157c7958c82ad75fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
+++
title = "C: the const modifier"
date = 2024-08-23

[extra]
latex = true
+++

---

### The `C` `const` modifier with nested pointers

The `const` is a way to tell the `C` compiler to consider the target variable read-only.
On function declaration, the data arguments are _de facto_ `const`, but we could specify the pointers' behavior as seen below.

_The key is to apply the `const` modifier from right to left_

```C
/* August 2024, C99.
 * Const modifier to data pointers.
 * Note: the patterns are just layers of Pascal's binomial triangle,
 *       easy to repete for a growing number of stars.
 */

/*
 * Zero star.
 */
/* Zero const modifier -> 1 choose 0. */
static int data;
/* One const modifier -> 1 choose 1. */
static int const constData;

/*
 * One star
 */
/* Zero const modifier -> 2 choose 0. */
static int *ptr_data;
/* One const modifier -> 2 choose 1. */
static int const *ptr_constData;
static int *const constPtr_data;
/* Two const modifiers -> 2 choose 2. */
static int const *const constPtr_constData;

/*
 * Two stars
 */
/* Zero const modifier -> 3 choose 0. */
static int **ptr_ptr_data;
/* One const modifier -> 3 choose 1. */
static int const **ptr_ptr_constData;
static int *const *ptr_constPtr_Data;
static int **const constPtr_ptr_Data;
/* Two const modifiers -> 3 choose 2. */
static int const *const *ptr_constPtr_constData;
static int const **const constPtr_ptr_constData;
static int *const *const constPtr_constPtr_data;
/* Three const modifiers -> 3 choose 3. */
static int const *const *const constPtr_constPtr_constData;

/*
 * Three stars
 */
/* Zero const modifier -> 4 choose 0. */
static int ***ptr_ptr_ptr_data;
/* One const modifier -> 4 choose 1. */
static int const ***ptr_ptr_ptr_constData;
static int *const **ptr_ptr_constPtr_data;
static int **const *ptr_constPtr_ptr_data;
static int ***const constPtr_ptr_ptr_data;
/* Two const modifiers -> 4 choose 2. */
static int const *const **ptr_ptr_constPtr_constData;
static int const **const *ptr_constPtr_ptr_constData;
static int const ***const constPtr_ptr_ptr_constData;
static int *const *const *ptr_constPtr_constPtr_data;
static int *const **const constPtr_ptr_constPtr_data;
static int **const *const constPtr_constPtr_ptr_data;
/* Three const modifiers -> 4 choose 3. */
static int const *const *const *ptr_constPtr_constPtr_constData;
static int const *const **const constPtr_ptr_constPtr_constData;
static int const **const *const constPtr_constPtr_ptr_constData;
static int *const *const *const constPtr_constPtr_constPtr_data;
/* Four const modifiers -> 4 choose 4. */
static int const *const *const *const constPtr_constPtr_constPtr_constData;
```

We can then do the same for following stars depth, but as we can see the number of possibilities is combinatorial: for \\(n\\) stars-pointers we will have \\(2^{n + 1}\\) `const` flavours possible.

You can verify the above assumptions by:

```C
#include <stddef.h>

void foo(int *ptr_data, int const *ptr_constData, int *const constPtr_data, int const *const constPtr_constData)
{
        *ptr_data = 0; // OK: modifies the pointed data
        ptr_data = NULL; // OK: modifies the pointer

        *ptr_constData = 0; // Error!
        ptr_constData = NULL; // OK: modifies the pointer

        *constPtr_data = 0; // OK: modifies the pointed data
        constPtr_data = NULL; // Error!

        *constPtr_constData = 0; // Error!
        constPtr_constData = NULL; // Error!
}
```