7

I have a piece of C code that looks like this:

const char (*foo)[2] = bar();

Now bar() is a function that returns a (const void *). How do I properly cast this const pointer? The code produces this warning from GCC :

"initialization discards qualifiers from pointer target type".   

Here are some of my unsuccessful attempts:

const char (*foo)[2] = (const char *)bar();
const char (*foo)[2] = (const void **)bar();

The original code does work, I just can't get rid of the warnings by properly casting the return value.

EDIT : This has been suggested:

const char (*foo)[2] = (const char (*)[2])bar();

It appears to be correct, but GCC gives this warning :

"cast discards qualifiers from pointer target type"   

which is nearly identical to the original warning.

EDIT 2 : OK, I think I've got it. The real problem here is the ( const void * ) definition of bar(). The const in the definition (const char( * )[2]) refers to the elements of the array, not the pointer to the array. This type definition is essentially an array, which when represented by a void pointer is not const. The real answer is that a ( const void * ) loses its const-ness when cast to (const char ( * )[2]).

4
  • 2
    Your question title says "array of const char pointers", but your assignment is to a pointer to an array of two chars. Can you clarify exactly what bar is supposed to return? Commented Nov 8, 2009 at 11:19
  • What version of gcc and what warning options are you using? Commented Nov 8, 2009 at 11:24
  • 1
    Must be new with 4.4.1, I don't get the warning with 4.4.0 -Wall -Wextra. Commented Nov 8, 2009 at 11:29
  • 1
    The issue is the need to cast to a const array type (not an array of const). The former is not possible in C (although they might as well be the same, the lack of lifting is arguably a bug in the standard). See my answer below for relevant links. Commented Nov 8, 2009 at 16:10

5 Answers 5

7

Several others have stated the correct cast, but it generates a spurious warning. That warning comes from a possible bug in the C standard, or (depending on your interpretation) a case that GCC should treat specially. I believe the const qualifier can be safely and unambiguously lifted to the array type. You can drop that warning with -Wno-cast-qual but of course that will eliminate warnings for cases that you actually care about.

To elaborate, the type const char (*)[2] means "pointer to array (length 2) of const char". The array is not marked const, just the elements of the array. When compared to the type const void *, the compiler notices that the latter is a pointer to const, where as the former is not, thus generating the warning. The C standard provides no way to mark an array as const, even though a const array would be equivalent to an array of const.

Sign up to request clarification or add additional context in comments.

1 Comment

@haccks It generates a warning with gcc -Wcast-qual.
3

Try:

const char (*foo)[2] = (const char (*)[2])bar();

Edit but if bar returns a pointer to a const array of char pointers as your question title hints, there should be no need for a cast if you assign to a variable of this type:

char* const* foo = bar();

Comments

3

The issue with the warning in the latest version of the cast has historical roots. You know that C language (as well as C++) correctly prohibits the T** -> const T** conversion. This is correct, since allowing this conversion would open the way for some subtle violations of const-correctness rules (can be found in any self-respecting FAQ).

However, C language also prohibits T** -> const T* const* conversion. This is different from C++, which allows this conversion. (This conversion doesn't violate const-correctness.) This has been long considered a "design defect" in C language specification. This defect has been "fixed" in C++, but it continues to persist in C (even in C99). Frankly, I have no idea why it was left unchanged in C99. One of the "fallouts" of that defect (or more precisely, of that approach to treating const-correctness) is that in C language the T (*)[N] -> const T (*)[N] conversion also remains prohibited, even though it carries no inherent threats to const-correctness.

I can't reproduce the warning you are getting with my version of GCC. But if you are getting it, it appears to be just another consequence of the same ideology. If you take into account that the conversion was requested by an explicit cast operator, the GCC warning is completely unjustified. You can try to work around the warning by using a chained cast

const char (*foo)[2] = (const char (*)[2]) (void *) bar();

1 Comment

Isn't const char (*foo)[2] = (void *) bar(); sufficient?
1

Just a note, you don't need the array dimensions:

const void *bar() { 
    static const char a[10] = "abcdefghij";
    return &a[4];
}

int main() {
    const char (*foo)[2] = (const char (*)[])bar();
    return 0;
}

Since this might be hard for some to read:

cdecl> explain const char (*foo)[2]
declare foo as pointer to array 2 of const char

3 Comments

If he knows that the return pointer actually returns a pointer to an array of arrays of 2 char, rather than just a pointer to an array of 2 char, then by keeping the array dimensions he can do valid pointer arithmetic on foo.
Good point I suppose, but that would only be useful if he had a 2D array of these things allocated in a contiguous block of memory and he knows from some other source the bounds of that 2D array relative to the pointer being returned. Doesn't seem likely in this case. On the flip side, omitting the dimension probably doesn't buy him anything, it's mostly just trivia I suppose. By the way, he's returning a pointer to an array of 2 chars, not "an array of arrays of 2 char". That would be const char (*foo)[][2] or as cdecl says: declare foo as pointer to array of array 2 of const char
Arrays are usually passed around by pointers to their first element, hence why const char(*foo)[2] might point to an array of arrays of 2 char. Or a more familiar example: \0 terminated strings are usually returned as char*, not char(*)[].
0
const char (*foo)[2] = (const char (*)[2])bar();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.