Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are char[] and char* as typedefs different, but sometimes... not?

Tags:

c++

decltype

The following observation arose as I was following this question about char[] and char* differences.

#include <iostream>

typedef char ar[];
typedef char* pr;
void f2(ar x, pr y)
{
    std::cout << std::is_same<decltype(x), decltype(y)>::value << '\n';
    std::cout << std::is_same<ar, pr>::value << '\n';
}

int main()
{
    char data[] = "data";
    char *ptr = data;
    f2(data,ptr);
    return 0;
}

Output ( on Apple LLVM version 4.2 (clang-425.0.28) )

1
0

Why do these report as different types, but not different decltype()s ? My suspicion is they are in fact different types due to their typedef declarations, but then why are variables reported as the same type?

like image 728
WhozCraig Avatar asked Sep 05 '13 00:09

WhozCraig


1 Answers

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:

  1. When the array expression is the operand of sizeof (sizeof arr yields the size of the array, not the size of a pointer);
  2. When the array expression is the operand of unary & (&arr is a pointer-to-array, not a pointer-to-pointer); and
  3. When the array expression is a string literal used to initialize an object of array type (char 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.

like image 196
Keith Thompson Avatar answered Oct 10 '22 05:10

Keith Thompson