Correctness - const
¶
Non-Modifiable Memory (1)¶
Did you know the difference?
void f(void)
{
char str[] = "blah";
str[0] = 'x';
}
void f(void)
{
char *str = "blah";
str[0] = 'x';
}
Non-Modifiable Memory (2)¶
char str[] = "blah";
|
char *str = "blah";
|
The const
Keyword (1)¶
So there is already the concept of read-only data …
Sadly compilers generally issue no warnings
(On Linux) Not an error, only on-demand duplication of a shared read-only memory page
⟶ expensive
Unintended in most cases
$ gcc -Wwrite-strings ...
warning: initialization discards ‘const’ qualifier from
pointer target type
A-ha: “const” qualifier!
The const
Keyword (2)¶
warning: initialization discards ‘const’ qualifier from
pointer target type
char *str = "blah";
Obviously (no surprise) the compiler knows that
"blah"
is in read-only memory⟶ String literals are
const char *
const char *str = "blah";
Consequences:
str
cannot be written to⟶ Code has to be fixed until compiler is happy
⟶ Correctness with minimal effort
const
Variables¶
Getting rid of the preprocessor (good idea) …
const int MAX_BUCKETS = 64;
… is the same, compiler-wise, as …
#define MAX_BUCKETS 64
Additional benefits …
MAX_BUCKETS
has a typeNot a stupid string substitution, but a regular C identifier
“unused” warnings
const
Parameters (1)¶
int sum(int *begin, int *end);
Reading this declaration, we assume the following:
It builds a
sum
It returns the result
It operates on a range
[begin, end)
It does not modify the input data
Ambiguity alert:
We can say nothing of the above for sure
… but we can help with the last item
const
Parameters (2)¶
int sum(const int *begin, const int *end);
Now we can say one thing for sure:
It does not modify the input data
Consequences:
sum()
has to modifiedNot a big deal when only a few lines involved
Can be a problem when code is large and complex
⟶ “
const
pollution”
Pointers, Pointers, Pointers … (1)¶
What’s known so far:
const
can be applied to scalar typesconst
can be applied tostruct
types (we don’t know this, but it’s a logical consequence)const
, applied to pointers, keeps me from modifying what they point to
const int i;
int const j; /* same! */
const int *pi = &i;
int const *pj = &j;
Pointers, Pointers, Pointers … (2)¶
Mixing …
int const i = 42;
int *pi = &i;
warning: initialization discards ‘const’ qualifier
from pointer target type
pi
does not promise to not modify the value it points toPointee is read-only
Sadly this can only be a warning for historical reasons
Pointers, Pointers, Pointers … (3)¶
So, given that …
int const i;
… is a read-only variable, …
int * const pi;
… is a read-only variable:
A pointer that cannot be modified
But can be used to modify what it points to (it’s an
int
, not anint const
)
Pointers, Pointers, Pointers … (4)¶
int * const pi;
/* error: assignment of read-only variable ‘pi’ */
pi = NULL;
/* ok, compiles */
*pi = 42;
But is this correct?
Pointers, Pointers, Pointers … (5)¶
So what’s this?
int i = 42
int const * const pi = &i;
/* error: assignment of read-only variable ‘pi’ */
pi = NULL;
/* error: assignment of read-only location ‘*pi’ */
*pi = 42;
Pointers, Pointers, Pointers … (6)¶
How about pointers that point to pointers?
int i = 42;
int *pi = &i;
int **ppi = π
**ppi = 7;
*ppi = NULL;
Pointers, Pointers, Pointers … (7)¶
How about pointers that point to pointers that point to
const
}? (Gosh)
int const i = 42;
int const *pi = &i;
int const **ppi = π
ppi = NULL;
*ppi = NULL;
/* error: assignment of read-only location ‘**ppi’ */
**ppi = 7;
Pointers, Pointers, Pointers … (8)¶
How about pointers that point to non-modifiable pointers that point
to const
?
int const i = 42;
int const * const pi = &i;
int const * const *ppi = π
ppi = NULL;
/* error: assignment of read-only location ‘*ppi’ */
*ppi = NULL;
/* error: assignment of read-only location ‘**ppi’ */
**ppi = 7;
Pointers, Pointers, Pointers … (9)¶
How about …? (To be continued)