Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot convert from XXX** to const XXX** [duplicate]

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?

like image 339
www.diwatu.com Avatar asked Feb 12 '14 18:02

www.diwatu.com


2 Answers

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.

like image 184
bames53 Avatar answered Nov 10 '22 01:11

bames53


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);
}
like image 40
Alex Avatar answered Nov 10 '22 02:11

Alex