4 ms·
> It would make sense that arr and arr2 are different types (as the thing on the left is different) while they are the same type and you should be able (hopeful
by netheril96 10y ago
> It would make sense that arr and arr2 are different types (as the thing on the left is different) while they are the same type and you should be able (hopefully!) to use them as arguments to the same function.
arr and arr2 are indeed distinct types. They are of type int[5] and int[7]. You can see this by checking that they have different sizes, or that `printf("%s\n", std::is_same<decltype(arr), decltype(arr2)>::value ? "true" : "false");` will outputs `false` on your screen.
Both of them decay into a pointer to int, that is why people commonly confuse them with pointers. But they are pointer types; they are distinct types on their own.
- pasquinelli 10y agoSizes aren't types though, and if I'm not mistaken that line of code is c++ no?
- netheril96 10y agoYes, it is c++, but both the concept of array and type decay comes from C.
- wahern 10y agoOn older versions of clang (including macOS 10.10 / Xcode 7.2) and, I believe, GCC this code #include <stdio.h> #define is_same(T, x) _Generic((x), T: "true", default: "false") int main(void) { int arr[5]; int arr2[7]; printf("arr === int[5] -> %s\n", is_same(int[5], arr)); printf("arr === int[7] -> %s\n", is_same(int[7], arr)); printf("arr2 === int[5] -> %s\n", is_same(int[5], arr2)); printf("arr2 === int[7] -> %s\n", is_same(int[7], arr2)); return 0; } produces arr === int[5] -> true arr === int[7] -> false arr2 === int[5] -> false arr2 === int[7] -> true Unfortunately either clang or GCC (I can't remember) decided the obvious behavior was wrong and changed it so that _Generic behaved as-if array expressions decayed to pointers. The C11 specification for _Generic was insufficiently precise, and for various reasons both vendors and (IIRC) the C committee are going to go with the least common denominator approach (just treat them like pointers) for consistency. So newer versions of clang and GCC print out all false. But another way of showing that arrays are real types is with #include <stdio.h> #define countof(a) (sizeof (a) / sizeof *(a)) int main(void) { int arr[5]; int arr2[7]; printf("countof(arr) -> %zu\n", countof(arr)); printf("countof(*&arr) -> %zu\n", countof(*&arr)); printf("countof(arr2) -> %zu\n", countof(arr2)); printf("countof(*&arr2) -> %zu\n", countof(*&arr2)); return 0; } which produces countof(arr) -> 5 countof(*&arr) -> 5 countof(arr2) -> 7 countof(*&arr2) -> 7 on all version of clang and GCC, and should on any other conformant C compiler. Although I would think that the simple sizeof proof should suffice to show that arrays are real types, notwithstanding that their evaluation rules are peculiar. Alas, the disaster with _Generic and array expressions only proves that the situation is less than ideal. Although part of the problem is that _Generic was a novel language feature that didn't fit neatly into the historical translation phases. IMO C++ gets a lot of things wrong about C semantics, but apparently they got decltype right (presuming the behavior is a product of a clearer specification, and that behavior is consistent across implementations). To be fair, although inelegant the compromise behavior for _Generic makes some sense. The principle use for _Generic is to implement crude function overloading. Because arrays always decay to pointers when passed to functions, it's convenient that _Generic would capture array expressions as pointers. OTOH, it makes some useful behaviors impossible. And the convenient behavior could have been had by manually coercing arrays to pointers using a trick like: #define decay(arr) ((0)? 0 : (arr)) #define is_same(T, x) _Generic(decay(x), ...)