Why can't I convert 'char**' to a 'const char* const*' in C?

The following code snippet (correctly) gives a warning in C and an error in C++ (using gcc & g++ respectively, tested with versions 3.4.5 and 4.2.1; MSVC does not seem to care):

char **a;
const char** b = a;

I can understand and accept this.
The C++ solution to this problem is to change b to be a const char * const *, which disallows reassignment of the pointers and prevents you from circumventing const-correctness (C++ FAQ).

char **a;
const char* const* b = a;

However, in pure C, the corrected version (using const char * const *) still gives a warning, and I don't understand why. Is there a way to get around this without using a cast?

To clarify:
1) Why does this generate a warning in C? It should be entirely const-safe, and the C++ compiler seems to recognize it as such.
2) What is the correct way to go about accepting this char** as a parameter while saying (and having the compiler enforce) that I will not be modifying the characters it points to? For example, if I wanted to write a function:

void f(const char* const* in) {
  // Only reads the data from in, does not write to it
}

And I wanted to invoke it on a char**, what would be the correct type for the parameter?

Edit: Thank you to those who have responded, particularly those who addressed the question and/or followed up on my responses.

I've accepted the answer that what I want to do cannot be done without a cast, regardless of whether or not it should be possible.


I had this same problem a few years ago and it irked me to no end.

The rules in C are more simply stated (ie they don't list exceptions like converting char** to const char*const* ). Consequenlty, it's just not allowed. With the C++ standard, they included more rules to allow cases like this.

In the end, it's just a problem in the C standard. I hope the next standard (or technical report) will address this.


> However, in pure C, this still gives a warning, and I don't understand why

You've already identified the problem -- this code is not const-correct. "Const correct" means that, except for const_cast and C-style casts removing const, you can never modify a const object through those const pointers or references.

The value of const-correctness -- const is there, in large part, to detect programmer errors. If you declare something as const, you're stating that you don't think it should be modified -- or at least, those with access to the const version only should not be able to modifying it. Consider:

void foo(const int*);

As declared, foo doesn't have permission to modify the integer pointed to by its argument.

If you're not sure why the code you posted isn't const-correct, consider the following code, only slightly different from HappyDude's code:

char *y;

char **a = &y; // a points to y
const char **b = a; // now b also points to y

// const protection has been violated, because:

const char x = 42; // x must never be modified
*b = &x; // the type of *b is const char *, so set it 
         //     with &x which is const char* ..
         //     ..  so y is set to &x... oops;
*y = 43; // y == &x... so attempting to modify const 
         //     variable.  oops!  undefined behavior!
cout << x << endl;

Non-const types can only convert to const types in particular ways to prevent any circumvention of 'const' on a data-type without an explicit cast.

Objects initially declared const are particularly special -- the compiler can assume they never change. However, if 'b' can be assigned the value of 'a' without a cast, then you could inadvertantly attempt to modify a const variable. This would not only break the check you asked the compiler to make, to disallow you from changing that variables value -- it would also allow you break the compiler optimizations!

On some compilers, this will print '42', on some '43', and others, the program will crash.

Edit-add:

HappyDude: Your comment is spot on. Either the C langauge, or the C compiler you're using, treats const char * const * fundamentally differently than the C++ language treats it. Perhaps consider silencing the compiler warning for this source line only.

Edit-delete: removed typo


To be considered compatible, the source pointer should be const in the immediately anterior indirection level. So, this will give you the warning in GCC:

char **a;
const char* const* b = a;

But this won't:

const char **a;
const char* const* b = a;

Alternatively, you can cast it:

char **a;
const char* const* b = (const char **)a;

You would need the same cast to invoke the function f() as you mentioned. As far as I know, there's no way to make an implicit conversion in this case (except in C++).

链接地址: http://www.djcxy.com/p/28354.html

上一篇: 投射void指针

下一篇: 为什么我不能在C中将'char **'转换为'const char * const *'?