3

I know about the char ** vs const char ** thing (like described in the c faq) but I can't see any scenario where doing so with a pointer to arrays would lead to some content inside the arrays themselves being actually modified.

My code:

void fun(const char (*p)[6])
{
    printf("%s", p[0]);
}

int main(int argc, char *argv[])
{
    char a[6] = "hello";
    char (*c)[6];

    c = &a;

    fun(c);
}

gives the below output when compiled with gcc:

test.c:17:9: warning: passing argument 1 of 'fun' from incompatible pointer type
test.c:5:10: note: expected 'const char (*)[6]' but argument is of type 'char (*)[6]'

The question here is somehow related but has no answer so far. Is it just the compiler being paranoïd and the only way to get rid of the warning is to explicitly cast ? Or is there really a chance something can go wrong ?

Community
  • 1
  • 1
mbonnin
  • 6,893
  • 3
  • 39
  • 55
  • Funny, I don't get any warnings. What flags are you compiling with? EDIT: It appears that clang is smart enough to not give me a warning about this, but GCC still does. Odd. – Richard J. Ross III Jun 27 '12 at 15:29
  • 2
    Possible duplicate of [Why can't I convert 'char**' to a 'const char* const*' in C?](http://stackoverflow.com/questions/78125/why-cant-i-convert-char-to-a-const-char-const-in-c) (it's the same rationale). – Oliver Charlesworth Jun 27 '12 at 15:41
  • @OliCharlesworth: yep looks like the same rationale indeed. So I guess I'm good for casting.. – mbonnin Jun 27 '12 at 15:47
  • Why same rationale? These two problems seem very different to me (@Oli maybe format your comment as an answer, if only just for me). – anatolyg Jun 27 '12 at 16:51
  • @anatolyg: as Oli says, the rationale is the same. That rationale is, "the C standard fails to define some implicit pointer conversions that are const-safe, and for that reason are defined in C++". The questions are different, but they are both of form "why can't I implicitly convert pointer type X to a more-constant type Y, even though it is const-safe to do so". Only X and Y differ, the answer is the same, and amounts to "because the C standard doesn't bother figuring out what's const-safe, and enabling it". – Steve Jessop Jun 27 '12 at 17:01
  • @anatolyg, Steve: Well, there's *that* rationale. But the one I'm referring to is the one given in the 2nd answer to the question I linked (also given at the FAQ [here](http://c-faq.com/ansi/constmismatch.html)). But perhaps I haven't thought about this sufficiently, and it doesn't apply here? – Oliver Charlesworth Jun 27 '12 at 17:04
  • @Oli: in that case I think you're mistaken. An implicit conversion `char** -> const char**` is "const-unsafe", meaning that if it existed you could modify a `const` object using code that contains no casts. So I agree with that part. `char (*)[6] -> const char(*)[6]` is const-safe for the same reason that if I define `struct Foo { char ra[6]; };`, then `Foo* -> const Foo*` is const-safe. `char ** -> const char * const *` is also const-safe, so that's the similarity *I* see between the questions. – Steve Jessop Jun 27 '12 at 17:10

3 Answers3

3

Const-conversion is covered by section 6.5.16.1 (1) of the standard:

  • both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;

In this case it looks like T is char [6] and the rest of the requirement clearly holds, as can be seen by modifying your example:

int main(int argc, char *argv[])
{
    typedef char c6[6];
    c6 a = "hello";
    const c6 *p = &a;
}

However this is actually not the case! This intersects with 6.7.3 (8):

If the specification of an array type includes any type qualifiers, the element type is so qualified, not the array type.

So const c6 * actually names the type const char (*)[6]; that is, pointer to array[6] of const char, not pointer to const array[6] of char.

Then the LHS points to the type const char[6], the RHS points to the type char[6], which are not compatible types, and the requirements for simple assignment do not hold.

ecatmur
  • 152,476
  • 27
  • 293
  • 366
3

It is just a quirk of C language specification. For another example, the char ** to const char *const * conversion is also safe from the const-correctness point of view, yet it is prohibited in C.

This quirk of const-correctness rules was "fixed" in C++ language, but C continues to stick to its original specification in this regard.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • It seems to me that in this case the the warning is a false positive, since assigning to arrays is not possible. Of course the warning is correct, but the code wouldn't compile without it. – 2501 Jul 09 '16 at 14:16
  • @2501: Where do you see "assigning to arrays" in this question? The whole thing is about pointer assignment. Both `c` and `p` are pointers, not arrays. – AnT stands with Russia Jul 09 '16 at 17:18
  • Think about the problem that occurs with char** , const char**, then try to reproduce this with pointers to arrays and you'll discover that an array assignment will have to be done. (I'll post an example later.) – 2501 Jul 09 '16 at 17:21
  • @2501: I don't see it. The problem with "char** to const char**" is sufficiently and immediately obvious to me. The popular example (from the FAQ) is not really *the* problem with "char** to const char**", it is just *one* popular illustration of *one* possible consequence of the actual problem. In this context, I still don't see how I am supposed to see "assignment of arrays" in this conversion. – AnT stands with Russia Jul 09 '16 at 19:43
  • In the above example, what type is `p[0]`. – 2501 Jul 09 '16 at 20:05
  • @2501: In the OP's example, `p[0]` is of type `const char [6]`, which in that context (argument of `printf`) immediately decays to `const char *`. But why? So far the body of the OP's `fun` was not really relevant to the discussion. The main issue was the conversion of `c` to `p`. – AnT stands with Russia Jul 09 '16 at 21:24
  • The issue is the original warning with conversion from const to non-const. Just like in this example: http://c-faq.com/ansi/constmismatch.html. If you try to recreate it with pointers to array instead of pointers to pointers, you will notice that an array assignment would have to be done. – 2501 Jul 10 '16 at 04:06
  • @2501: Yes, as I said above, the original warning is about the conversion of argument `c` to parameter `p`. At the FAQ link you provided the issue is the `const char **p2 = &p1;` line. Only this line and nothing else. The rest of the example at the FAQ link is just an example that illustrates one possible *consequence* of that issue. As for our case... Why I'd want to "recreate" that example in this case is not clear to me. The fact that I'd run into "array assignment" would simply indicate that that FAQ illustration it is inapplicable and irrelevant in our case. It cannot be "recreated". – AnT stands with Russia Jul 10 '16 at 07:33
-1

Actually the reasons are quite similar (char ** vs. pointer of arrays).

For what you are trying to do, the following would suffice (and it works):

void fun(const char *p)
{
    printf("%s", p);
}

int main(int argc, char *argv[])
{
    char a[6] = "hello";
    char *c;

    c = a;

    fun(c);
}

With what you are trying to do, it would be possible to modify the values as follows that defeats the purpose (just an example):

void morefun(const char *p[6])
{
    char d;
    char *p1 = &d;
    p[1] = p1;
    *p1 = 'X';
    printf("\nThe char is %c\n", *p[1]);
}

int main(int argc, char *argv[])
{
    const char *d[6];

    morefun(d);
}
  • 2
    Your example is incorrect; the argument to `morefun` should be `const char (*p)[6]`, not `const char *p[6]`. – ecatmur Jun 27 '12 at 16:59
  • also p[1] = p1 will output a warning I guess... My point was not just to write "hello" but to understand the reason of the initial warning. – mbonnin Jun 27 '12 at 17:55