Laj*_*agy 15 c++ c-preprocessor
OK,我不完全是一个新手,但我不能说我理解下面的宏.最令人困惑的部分是将值转换为size_t:这实际上是什么?特别是,因为我看到一个否定运算符,据我所知,它可能导致零值.这是不是意味着它会导致被零除错误?(顺便说一句,宏是正确的,并且工作得很漂亮.)
#define ARRAYSIZE(a) \
((sizeof(a) / sizeof(*(a))) / \
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
Run Code Online (Sandbox Code Playgroud)
Oli*_*rth 13
第一部分(sizeof(a) / sizeof(*(a)))
相当简单; 它将整个数组的大小(假设您通过宏传递数组类型的对象,而不是指针)除以第一个元素的大小.这给出了数组中元素的数量.
第二部分不是那么简单.我认为潜在的归零是有意的; 如果由于某种原因,数组的大小不是其中一个元素的整数倍,它将导致编译时错误.换句话说,它是某种编译时健全性检查.
但是,我无法看到在什么情况下可能发生这种情况......正如人们在下面的评论中提出的那样,它会捕获一些误用(比如ARRAYSIZE()
在指针上使用).但是,它不会捕获所有这样的错误.
最后的划分似乎是尝试检测非数组参数(例如指针).
例如,它无法检测到char*
,但是对于大于指针大小的T*
位置会起作用sizeof(T)
.
在C++中,通常更喜欢以下函数模板:
typedef ptrdiff_t Size;
template< class Type, Size n >
Size countOf( Type (&)[n] ) { return n; }
Run Code Online (Sandbox Code Playgroud)
此函数模板无法使用指针参数进行实例化,只能使用数组.在C++ 11中,它也可以用std::begin
和表示std::end
,它自动地使它也适用于具有随机访问迭代器的标准容器.
限制:对于C++ 03中的本地类型数组不起作用,并且不会产生编译时间大小.
对于编译时间大小,您可以改为
template< Size n > struct Sizer { char elems[n]; };
template< class Type, size n >
Sizer<n> countOf_( Type (&)[n] );
#define COUNT_OF( a ) sizeof( countOf_( a ).elems )
Run Code Online (Sandbox Code Playgroud)
免责声明:所有代码都不受编译器的影响.
但一般来说,只需使用第一个功能模板,countOf
.
干杯和hth.
我写了这个宏的这个版本。考虑旧版本:
#include <sys/stat.h>
#define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a)))
int main(int argc, char *argv[]) {
struct stat stats[32];
std::cout << "sizeof stats = " << (sizeof stats) << "\n";
std::cout << "sizeof *stats = " << (sizeof *stats) << "\n";
std::cout << "ARRAYSIZE=" << ARRAYSIZE(stats) << "\n";
foo(stats);
}
void foo(struct stat stats[32]) {
std::cout << "sizeof stats = " << (sizeof stats) << "\n";
std::cout << "sizeof *stats = " << (sizeof *stats) << "\n";
std::cout << "ARRAYSIZE=" << ARRAYSIZE(stats) << "\n";
}
Run Code Online (Sandbox Code Playgroud)
在 64 位机器上,此代码产生以下输出:
sizeof stats = 4608
sizeof *stats = 144
ARRAYSIZE=32
sizeof stats = 8
sizeof *stats = 144
ARRAYSIZE=0
Run Code Online (Sandbox Code Playgroud)
这是怎么回事?ARRAYSIZE 是如何从 32 变为 0 的?好吧,问题是函数参数实际上是一个指针,即使它看起来像一个数组。所以在 foo 里面,"sizeof(stats)" 是 8 个字节,而 "sizeof(*stats)" 仍然是 144。
使用新宏:
#define ARRAYSIZE(a) \
((sizeof(a) / sizeof(*(a))) / \
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
Run Code Online (Sandbox Code Playgroud)
当 sizeof(a) 不是 sizeof(* (a)) 的倍数时,% 不为零,即 ! 反转,然后 static_cast 计算为零,导致编译时除以零。因此,在宏中可能的范围内,这种奇怪的划分会在编译时捕获问题。
PS:在 C++17 中,只使用 std::size,参见http://en.cppreference.com/w/cpp/iterator/size