I have the very simple code in c++. When I compile under Visual studio, the error happens.
#include <stdint.h>
#include <time.h>
void func1(const uint8_t* data)
{
}
void func2(const uint8_t** data)
{
}
int main()
{
uint8_t* data1 = NULL;
uint8_t** data2 = NULL;
func1(data1);//OK
func2(data2);//error C2664: cannot convert argument 1 from 'uint8_t **' to 'const uint8_t **'
}
the full error meesage is:
error C2664: 'void func2(const uint8_t **)' : cannot convert argument 1 from 'uint8_t **' to 'const uint8_t **'
Usualy you cannot convert const XXX to XXX, but from XXX to const XXX should be OK, Why this error happens here?
but from XXX to const XXX should be OK
No, this isn't okay in this specific instance. Consider:
int const x = 10; // implementation stores to read-only memory
// implementation crashes on writes to read-only memory
void foo(int const **ptr) {
*ptr = &x;
}
int main() {
int *p;
foo(&p);
*p = 12; // crash
}
If this were legal it would assign a 'pointer to const' value to a 'pointer to non-const' object, and therefore enable dangerous writing to constant objects.
For a conversion to const to be okay const must be added at every level in the type above where the lowest const is added (except the very top).
For example it's not okay to convert int ******
to int ***const***
, but it is okay to convert it to int ***const*const*const*
. This also applies to volatile
: you can convert int ******
to int ***volatile*const*const*
but not int ***volatile***
This rule in the type system protects us from mistakenly treating const objects as non-const, or volatile objects as non-volatile, and if we really want to make this mistake then we have to use const_cast
.
foo(const_cast<int const **>(&p));
*p = 12; // crash
With const cast the program is well formed and the compiler happily produces an executable that exhibits undefined behavior. (live example)
Fixing foo()
to allow it to take a pointer to non-const:
void foo(int const * const *ptr) {
*ptr = &x; // error, can't modify *ptr
}
foo(&p); // conversion works fine
prevents foo()
from writing a 'pointer to const' value into a 'pointer to non-const' object. (live example)
You probably got the idea that XXX to const XXX is okay because the most common case of this, i.e. with single level pointers: int *
-> int const *
, is okay and also obeys the above conversion rule. const
at the very top level doesn't matter because changes to the parameter itself won't escape the function.
When you use const to pointer of pointer you need to use uint8_t const* const*
#include <stdint.h>
#include <time.h>
void func1(const uint8_t* data) {
}
void func2( uint8_t const* const* data ) {
}
int main() {
uint8_t* data1 = NULL;
uint8_t** data2 = NULL;
func1(data1);//OK
func2(data2);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With