The following observation arose as I was following this question about char[]
and char*
differences.
#include
typ
The C family is pass-by-value, and the C value of an array is a pointer to its first element. When you pass an item declared to be an array to a function, what's really getting passed is that pointer, and C treats the prototype as if you declared it that way.
I changed the code so that we could see how calling a f2 changes the type. Before the call the variables are of different type. After the call they have become same
typedef char ar[];
typedef char* pr;
void f2(ar x, pr y)
{
cout << is_same<decltype(x), decltype(y)>::value << '\n'; //same type
}
int main()
{
ar data = "data";
pr ptr = data;
cout << is_same<decltype(data), decltype(ptr)>::value << '\n'; // different
f2(data,ptr);
return 0;
}
the output is 0 0 .As @jthill, @Dyp and @keith Thompson says this is because of decaying of the array to pointer.
In C++, as in C, a parameter that's declared to be of array type is adjusted (at compile time) to be of pointer type, specifically a pointer to the array's element type.
This happens whether the array type is specified directly or via a typedef (remember that a typedef doesn't create a new type, just an alias for an existing type).
So this:
typedef char ar[];
typedef char* pr;
void f2(ar x, pr y)
{
// ...
}
really means:
void f2(char* x, char* y)
{
// ...
}
Another rule, also shared by C and C++, is that an expression of array type is, in most but not all contexts, implicitly converted to a pointer to the first element of the array object. Which means that if you define an array object:
char arr[10];
you can use the name of that object as an argument to a function that takes a char*
parameter (which loses the bounds information).
In C, the cases where this implicit conversion doesn't happen are:
sizeof
(sizeof arr
yields the size of the array, not the size of a pointer);&
(&arr
is a pointer-to-array, not a pointer-to-pointer); andchar s[] = "hello";
initializes s
as an array, not as a pointer).None of these cases (or the other cases that occur in C++) appear in your program, so your call:
f2(data,ptr);
passes two pointer values of type char*
to f2
.
Inside f2
, the parameter objects x
and y
are both of type char*
, so std::is_same<decltype(x), decltype(y)>::value
is true.
But the types ar
and pr
are distinct. ar
is an incomplete array type char[]
, and pr
is the pointer type char*
.
Which explains your program's output. The weirdness happens because the parameter x
, which you defined with the array type ar
, is really of type char*
, which is the same type as pr
.