The following code warns about incompatible type. What is the proper way to solve this code?
thanks
typedef struct a_struct struct_type;
void f(cons
Edited based on Rampion's answer. The problem is with the double const in f()'s declaration.
Code with the warning:
struct_type ** v;
v = (struct_type **)malloc(10 * sizeof(struct_type *));
f(v);
This compiles without warning:
const struct_type *const* v;
v = (const struct_type **)malloc(10 * sizeof(struct_type *));
f(v);
f expects to get as input an array of pointers (const struct_type* []). You pass a pointer to a pointer of struct (const struct_type**).
The best thing to do, IMO, is to change the signature of f to:
void f(const struct_type *const* data);
Why do you need to pass arrays as arguments to functions?
See if this would work for you:
f(struct_type *data);
void test(unsigned n)
{
struct_type *v = malloc(n * sizeof(struct_type *));
f(v);
}
Please let me know how you get on.
The reason the compiler is complaining is the first const in f's declaration.
Try using
void f(struct_type *const data[], unsigned n);
/*...*/
f( v, n );
and you won't get the same warning. Alternatively, you could cast v when you call f
void f(const struct_type *const data[], unsigned n);
/*...*/
f( (const struct_type * const *) v, n );
This is a little counterintuitive, but in C, you can't pass a pointer-to-pointer-to-nonconst for a pointer-to-pointer-to-const. They made a special exception to allow you to pass a pointer-to-nonconst for a pointer-to-const.
Here's a FAQ question "Why can't I pass a char ** to a function which expects a const char **?":
You can use a
pointer-to-T(for any typeT) where apointer-to-const-Tis expected. However, the rule (an explicit exception) which permits slight mismatches in qualified pointer types is not applied recursively, but only at the top level. (const char **ispointer-to-pointer-to-const-char, and the exception therefore does not apply.)The reason that you cannot assign a
char **value to aconst char **pointer is somewhat obscure. Given that theconstqualifier exists at all, the compiler would like to help you keep your promises not to modifyconstvalues. That's why you can assign achar *to aconst char *, but not the other way around: it's clearly safe to addconst-ness to a simple pointer, but it would be dangerous to take it away. However, suppose you performed the following more complicated series of assignments:const char c = 'x'; /* 1 */ char *p1; /* 2 */ const char **p2 = &p1; /* 3 */ *p2 = &c; /* 4 */ *p1 = 'X'; /* 5 */In line 3, we assign a
char **to aconst char **. (The compiler should complain.) In line 4, we assign aconst char *to aconst char *; this is clearly legal. In line 5, we modify what achar *points to--this is supposed to be legal. However, p1 ends up pointing to c, which isconst. This came about in line 4, because *p2 was really p1. This was set up in line 3, which is an assignment of a form that is disallowed, and this is exactly why line 3 is disallowed.Assigning a
char **to aconst char **(as in line 3, and in the original question) is not immediately dangerous. But it sets up a situation in which p2's promise--that the ultimately-pointed-to value won't be modified--cannot be kept.(C++ has more complicated rules for assigning
const-qualified pointers which let you make more kinds of assignments without incurring warnings, but still protect against inadvertent attempts to modifyconstvalues. C++ would still not allow assigning achar **to aconst char **, but it would let you get away with assigning achar **to aconst char * const*.)In C, if you must assign or pass pointers which have qualifier mismatches at other than the first level of indirection, you must use explicit casts (e.g. (
const char **) in this case), although as always, the need for such a cast may indicate a deeper problem which the cast doesn't really fix.References: ISO Sec. 6.1.2.6, Sec. 6.3.16.1, Sec. 6.5.3 H&S Sec. 7.9.1 pp. 221-2