I've been getting this warning:
note: expected ‘const char **’ but argument is of type ‘char **’
For now, I'm passing the arguments by casting them to const char **
. Is there any other way I can get rid of it?
I've been getting this warning:
note: expected ‘const char **’ but argument is of type ‘char **’
For now, I'm passing the arguments by casting them to const char **
. Is there any other way I can get rid of it?
edit: I even answered the wrong question. My answer is completely irrelevant! Ignore me please.
edit 2: after the gentleman question asker clarifies his question, it turns out that my answer is in fact relevant. C'est la vie.
This is a fun bit of C, which makes sense if you think hard enough about it.
Basically, the conversion:
is not allowed.
Why, you might ask? "I'm making things more const! This is obviously a good thing!"
Well, think about this. If that were allowed, then:
BAM you're dead. So... no :-)
The warning tells you that the function you're calling expects the given parameter as
const char**
but you're passing achar**
parameter. To get rid of this warning you couldconst char**
const char**
(like you're currently doing)char**
Short Answer
Can you safely typecast
char **
toconst char**
? No. (Not safely anyway), and the reason is far more subtle than you may think. Can you get rid of it another way? Sure. Load an array ofconst char*
values from yourchar*
values and pass that instead. (or change the callee prototype, but thats cheating =P).Consider the following code, which essentially does everything you're wishing except invoke a function. The marked line demonstrates the equivalent point-of-cast
It takes awhile to really stare at this, and admittedly I didn't see it at first either. @sheu did a solid job of catching it about 24 hours before I really thought about it long enough to realize he was right all along (and I actually upvoted that answer before writing this one). Then I thought he was wrong about the same time he thought his answer wasn't applicable. Turns out we were both wrong on that leap, because he was right the first time, I was wrong the second time, and now... ugh.
On VS2012 and VS2010 both the marked line will flag an error without a cast. clang will compile it with a warning in C, but allow it (which I found surprising). Given, you do have to really step out of your happy place to break it, but it is still none-the-less broken.
The rest of this is a diatribe on identifying pointer types, their constness, and what is equivalent to what.
Long Diatribe on Pointers And Const
The warning is because
char **
andconst char **
are not equivalent (duh). To be correct, you could fix the prototype (callee), or fix the caller (by loading an array ofconst char *
and passing that). But can you safely typecast the first to the second? Hmmm....Remember, by the standard
const
goes to the item immediately to its left. Declaring it on the most-left of a data type is a nicety that the language supports, but often introduces confusion or problems. As a rule-of-thumb, ifconst
appears on the far-left of a decl immediately before the type, it applies to the data type; not the subsequent pointer (if any). When it appears to the right of anything it applies to the immediate-left decl-part, be it a data type part or a pointer part, but no matter what it only applies to a single part.A plethora of samples follows:
No Indirection:
Single-Indirection:
Double Indirection:
And of course who can leave home without...
So how does this affect your question? When compiling that code in C, without a cast you'll get a compiler warning (or error if compiling with
-Werror
). When compiling in C++, you'll just plain error because the parameter signature doesn't match. But why?Because these have no direct equivalence:
When compiling with clang, the exact warning in C is given as:
VS2010 and VS2012 both, on the other hand, toss an error:
It seems odd, but VS is actually more correct (wonders never cease).
And that makes perfect sense. Nestled down in the type declaration is the fact that the first of these does not allow modification to the final data, the second does. From above we know that
char **
andconst char **
(aka.char const **
), are not the same. At the bottom of one is a pointer to aconst char
, while the other has a pointer tochar
.