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 notconst. The real answer is that a ( const void * ) loses its const-ness when cast to (const char ( * )[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?
–
Charles BaileyNov 8 '09 at 11:19

What version of gcc and what warning options are you using?
–
Charles BaileyNov 8 '09 at 11:24

Must be new with 4.4.1, I don't get the warning with 4.4.0 -Wall -Wextra.
–
Charles BaileyNov 8 '09 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.
–
JedNov 8 '09 at 16:10

5 Answers
5

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 constchar". 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.

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

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.
–
Charles BaileyNov 8 '09 at 11:32

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
–
Robert S. BarnesNov 8 '09 at 11:50

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(*)[].
–
Charles BaileyNov 8 '09 at 12:15