1. 13
    1. 7

      One loosely related trick I found quite recently is that C++ lets you template on array size, which lets you overload things that take a buffer + size to only take the buffer (can’t do it in plain C), and also lets you implement an ARRAY_COUNT macro that doesn’t compile if you use it on pointers.

      template< typename T, size_t N >
      char ( &ArrayCountObj( const T ( & )[ N ] ) )[ N ];
      #define ARRAY_COUNT( arr ) ( sizeof( ArrayCountObj( arr ) ) )
      

      I believe that declares a function returning an array of N chars? Anyway the error you get is crap but it does work (int * a; ARRAY_COUNT( a )):

      main.cc: In function ‘int main()’:
      main.cc:5:57: error: no matching function for call to ‘ArrayCountObj(int*&)’
       #define ARRAY_COUNT( arr ) ( sizeof( ArrayCountObj( arr ) ) )
                                                               ^
      main.cc:9:9: note: in expansion of macro ‘ARRAY_COUNT’
        return ARRAY_COUNT( a );
               ^~~~~~~~~~~
      main.cc:4:9: note: candidate: template<class T, long unsigned int N> char (& ArrayCountObj(const T (&)[N]))[N]
       char ( &ArrayCountObj( const T ( & )[ N ] ) )[ N ];
               ^~~~~~~~~~~~~
      main.cc:4:9: note:   template argument deduction/substitution failed:
      main.cc:5:57: note:   mismatched types ‘const T [N]’ and ‘int*’
       #define ARRAY_COUNT( arr ) ( sizeof( ArrayCountObj( arr ) ) )
                                                               ^
      main.cc:9:9: note: in expansion of macro ‘ARRAY_COUNT’
        return ARRAY_COUNT( a );
               ^~~~~~~~~~~
      
      1. 4

        Cool! If you can use a C++14 compiler (C++11 is probably good enough, but can’t recall the history of constexpr rules), you can write a constexpr function template which does the same:

        template <typename T, size_t N>
        constexpr size_t ARRAY_COUNT(const T(&)[N]) {
            return N;
        }
        

        (ideone)

        As for the error message, I wonder if you could do something nasty with SFINAE and static_assert to improve that.

      2. 1

        OT, we need colorized syntax highlighting on Lobsters.

        1. 2

          Unfortunately C++ (e.g. template< typename T, size_t N > char ( &ArrayCountObj( const T ( & )[ N ] ) )[ N ];) is unreadable with syntax highlighting too.

      3. 1

        Note that with some GCC extensions you can implement an array-count macro that rejects pointers (or any non-array type, really) in C…from the Linux kernel:

        #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
        #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
        #define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
        #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
        
    2. 4

      This old Reddit comment explains what’s going on: https://www.reddit.com/r/programming/comments/1scchh/the_difference_between_arr_and_arr_how_to_find/cdwjgup/

      tl;dr: the size of the array is contained in the array pointer’s type

    3. 1

      I guess it could be used as a more succinct way of getting a pointer to the end of a C array. Though it’s mostly in C++ that you use begin and end instead of pointer and size (and in C++ you have std::end for this):

      int arr[3] = { 7, 3, 5 };
      
      // These all do the same    
      std::sort(arr, (&arr)[1]);
      std::sort(arr, arr + sizeof(arr) / sizeof(arr[0]));
      std::sort(std::begin(arr), std::end(arr));