Following fizzer's post at C++ constructs replacing C constructs, I'll write here my answer:
Warning: The C++ solution proposed below is not standard C++, but is an extension to g++ and Visual C++, and is proposed as a standard for C++0x (Thanks to Fizzer's comments about this)
Note that Johannes Schaub - litb's answer offers another, C++03 compliant way to do it anyway.
Question
How to extract the size of a C array?
Proposed C solution
Source: When are C++ macros beneficial?
#define ARRAY_SIZE(arr) (sizeof arr / sizeof arr[0])
Unlike the 'preferred' template solution discussed in a current thread, you can use it as a constant expression:
char src[23];
int dest[ARRAY_SIZE(src)];
I disagree with Fizzer as there is a templated solution able to generate a constant expression (In fact, a very interesting part of templates is their capacity to generate constant expressions at compilation)
Anyway, ARRAY_SIZE is a macro able to extract the size of a C array. I won't elaborate about the macros in C++: The aim is to find an equal or better C++ solution.
A better C++ solution?
The following C++ version has none of the macro problems, and can do anything the same way:
template <typename T, size_t size>
inline size_t array_size(T (&p)[size])
{
// return sizeof(p)/sizeof(p[0]) ;
return size ; // corrected after Konrad Rudolph's comment.
}
demonstration
As demonstrated by the following code:
#include <iostream>
// C-like macro
#define ARRAY_SIZE(arr) (sizeof arr / sizeof arr[0])
// C++ replacement
template <typename T, size_t size>
inline size_t array_size(T (&p)[size])
{
// return sizeof(p)/sizeof(p[0]) ;
return size ; // corrected after Konrad Rudolph's comment.
}
int main(int argc, char **argv)
{
char src[23];
char * src2 = new char[23] ;
int dest[ARRAY_SIZE(src)];
int dest2[array_size(src)];
std::cout << "ARRAY_SIZE(src) : " << ARRAY_SIZE(src) << std::endl ;
std::cout << "array_size(src) : " << array_size(src) << std::endl ;
std::cout << "ARRAY_SIZE(src2) : " << ARRAY_SIZE(src2) << std::endl ;
// The next line won't compile
//std::cout << "array_size(src2) : " << array_size(src2) << std::endl ;
return 0;
}
This will output:
ARRAY_SIZE(src) : 23
array_size(src) : 23
ARRAY_SIZE(src2) : 4
In the code above, the macro mistook a pointer for an array, and thus, returned a wrong value (4, instead of 23). The template, instead, refused to compile:
/main.cpp|539|error: no matching function for call to ‘array_size(char*&)’|
Thus demonstrating that the template solution is:
* able to generate constant expression at compile time
* able to stop the compilation if used in the wrong way
Conclusion
Thus, all in all, the arguments for the template is:
- no macro-like pollution of code
- can be hidden inside a namespace
- can protect from wrong type evaluation (a pointer to memory is not an array)
Note: Thanks for Microsoft implementation of strcpy_s for C++... I knew this would serve me one day... ^_^
http://msdn.microsoft.com/en-us/library/td1esda9.aspx
Edit: The solution is an extension standardized for C++0x
Fizzer did rightly comment this was not valid in the current C++ standard, and was quite true (as I could verify on g++ with -pedantic option checked).
Still, not only this is usable today on two major compilers (i.e. Visual C++ and g++), but this was considered for C++0x, as proposed in the following drafts:
The only change for C++0x being probably something like:
inline template <typename T, size_t size>
constexpr size_t array_size(T (&p)[size])
{
//return sizeof(p)/sizeof(p[0]) ;
return size ; // corrected after Konrad Rudolph's comment.
}
(note the constexpr keyword)
Edit 2
Johannes Schaub - litb's answer offers another, C++03 compliant way to do it. I'll copy paste the source here for reference, but do visit his answer for a complete example (and upmod it!):
template<typename T, size_t N> char (& array_size(T(&)[N]) )[N];
Which is used as:
int p[] = { 1, 2, 3, 4, 5, 6 };
int u[sizeof array_size(p)]; // we get the size (6) at compile time.
Many neurons in my brain fried to make me understand the nature of array_size
(hint: it's a function returning a reference to an array of N chars).
:-)