0

If we have void foo(const char * const ** bar); and we call it with char *** bar = malloc(...); such as foo((const char * const **) bar); It returns:

error: to be safe all intermediate pointers in cast from ‘char ***’ to ‘const char * const**’ must be ‘const’ qualified [-Werror=cast-qual]

Trying to pass it in without casting results in a type warning, but passing a char * into a const char * works, I can also pass a char *** into a char ** const * function parameter, but I want more read-only qualifier than just a single level.

The intent is that the function assumes the entire pointer data and pointer being passed in are read-only, such that the pointer won't be written to in any way.

I understand that the flag is an extra one, but it's defined as:

-Wcast-qual

Warn whenever a pointer is cast so as to remove a type qualifier from the target type. For example, warn if a const char * is cast to an ordinary char *.

As far as I can tell, no type qualifier is being removed, rather we're adding type qualifiers to let the user know that the function doesn't change any data.

Why is the previously mentioned code triggering the extra warning -Wcast-qual? Is there a better way of going about passing a completely malloc'd triple pointer as a read-only function?

Ray C
  • 547
  • 2
  • 7
  • 24
  • `Is there a better way of going about passing a completely malloc'd triple pointer as a read-only function?` Yes, don't cast `malloc` at all – David Ranieri Oct 17 '16 at 15:53
  • Casting raises a "incompatible pointer type" error. I actually agree, it makes no sense to cast, but for some reason the compiler won't allow it. EDIT: Is a const char * const ** not the same type as char *** just with qualifiers? – Ray C Oct 17 '16 at 15:54
  • Are you compiling with a C++ compiler? – David Ranieri Oct 17 '16 at 15:55
  • 1
    @jake Related, it may help if you make the problem just a wee bit simpler. See [Why does passing `char**` as `const char**` generate a warning?](https://stackoverflow.com/questions/14562845/why-does-passing-char-as-const-char-generate-a-warning), – WhozCraig Oct 17 '16 at 16:01
  • Compiling with GCC 5.2.1 std=c11 so a C compiler – Ray C Oct 17 '16 at 16:16
  • "Is there a better way of going about passing a completely malloc'd triple pointer as a read-only function?" --> Why not `const char * const ** bar = malloc(sizeof *bar * N); foo2(bar);` and avoid all casting? – chux - Reinstate Monica Oct 17 '16 at 16:29
  • I can't do that because I wish to actually malloc further and give all cells memory. If I try to do `bar[0] = malloc` I'll get `assignment of read-only location`. Also, I think mallocing into const memory is considered bad practice because you're going to free it later, so it should never be read-only. – Ray C Oct 17 '16 at 16:33
  • `bar[0] = malloc(...)` is not a problem. `bar[0][0] = malloc()` is an issue. As "The intent is that the function assumes the entire pointer data and pointer being passed in are read-only" I suspect you wanted another `const` --> `foo(const char * const * const * bar)` – chux - Reinstate Monica Oct 17 '16 at 16:36
  • 1
    Does this work for you? 1) `foo(const char * const ** bar)` --> `foo(const char * const * const * bar)` 2) `foo((const char * const **) bar);` --> `foo((const char * const * const*) bar);`. Add `const` to both function and cast. – chux - Reinstate Monica Oct 17 '16 at 16:48
  • Chux, that seems to work. Thank you very much. Can you make that an answer fully and I can reward you the points. I didn't realize that the `const **` != `const * const *` – Ray C Oct 17 '16 at 18:49

2 Answers2

1

Why does passing a char* to a function that expects a char const* work?

It's simple to understand that. You are not able to modify the string in the called function. That's OK.

Why does passing a char** to a function that expects a char const** not work?

This sounds non-intuitive but there is a reason. Take this analogy with an int.

const int a = 10;
void foo(int const ** ap)
{
   *ap = &a;
}

void bar()
{
   int * p = NULL;
   foo(&p);
   *p = 20;
}

If you were allowed to use that, you are able to modify a, which is const, in bar indirectly.

That's why &p, whose type is int**, is not allowed to be cast to int const** implicitly.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • Is there a way to specify that ap won't be copied to another pointer? Such as using the `restrict` keyword? Or are there more scenarios. – Ray C Oct 17 '16 at 16:17
  • @jake, I don't think use of `restrict` is going to resolve the `const` vs non-`const` issue. – R Sahu Oct 17 '16 at 16:33
  • I just tried it and it seemed not to work. I guess my logic was `restrict` says that only the given pointer will point at memory, but that doesn't really work and it doesn't fix the issue at hand. – Ray C Oct 17 '16 at 16:36
0

TL;DR: const char * const ** -> const char * const * const *

To finish the question, answered in the comments by /users/2410359/chux (asked them to make a post, but they haven't). The solution was to use a const char * const * const * which does not trigger the -Wcast-qual flag. Basically what I had was not true read-only qualifiers, I needed another level.

Ray C
  • 547
  • 2
  • 7
  • 24