My XCode (default compiler should be clang?) shows me on this code a warning:
Incompatible pointer types passing 'char *(*)[2]' to parameter of type 'char ***'
(when calling func)
void func (char ***arrayref, register size_t size) {
/// ...
}
int main()
{
char *array[2] = {"string", "value"};
func(&array, 2);
}
while this code is no problem (=no warning):
void func (char **arrayref, register size_t size) {
/// ...
}
int main()
{
char *array[2] = {"string", "value"};
func(array, 2);
}
While this removes the warning
func((char***)&array, 2);
I still don't know why the first emits a warning, while the latter doesn't.
Also, when the first is a problem, I'd also expect that the first emits a warning like:
Incompatible pointer types passing 'char *[2]' to parameter of type 'char **'
Time for a brief refresher on array semantics.
Except when it is the operand of the sizeof
or unary &
operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T
" will be converted ("decay") to an expression of type "pointer to T
", and the value of the expression will be the address of the first element in the array.
The expression array
in your code has type "2-element array of char *
", or char *[2]
. When you pass it as an argument to func
, as in
func( array, 2 );
the expression is converted to an expression of type "pointer to char *
", or char **
, which is the type your function is expecting, and the value of the expression is the address of the first element: array == &array[0]
. This is why you don't get the warning for the second code snippet.
In the first snippet, the array is an operand of the unary &
operator, so the conversion to a pointer type doesn't happen; instead, the type of the expression is "pointer to 2-element array of char *
", or char *(*)[2]
, which is not compatible with char **
. The address value is the same (the address of the first element of the array is the same as the address of the array itself), but the types don't match, hence the warning.
So why does this matter? A pointer is just an address, and all address are the same, right? Well, no. A pointer is an abstraction of an address, with associated type semantics. Pointers to different types don't have to have the same size or representation, and pointer arithmetic depends on the type of the pointed-to type.
For example, if I declare a pointer as char **p;
, then the expression p++
will advance the pointer to point to the next object of type char *
, or sizeof (char *)
bytes from the current address. If p
is declared as char *(*p)[2]
, however, the expression p++
will advance p
to point to the next two-element array of char *
, which is 2 * sizeof (char *)
bytes from the current address.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments