Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/145.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 排列C++;宏:它是如何工作的?_C++_C Preprocessor - Fatal编程技术网

C++ 排列C++;宏:它是如何工作的?

C++ 排列C++;宏:它是如何工作的?,c++,c-preprocessor,C++,C Preprocessor,好的,我不是一个完全的新手,但是我不能说我理解下面的宏。最令人困惑的部分是价值大小的划分:这到底能实现什么?特别是,因为我看到了一个否定运算符,据我所知,它可能会导致一个零值。这是否意味着它可以导致零除误差?(顺便说一句,宏是正确的,工作起来很漂亮。) #定义数组大小(a)\ ((sizeof(a)/sizeof(*(a)))/\ 静态施法(!(sizeof(a)%sizeof(*(a)щщ)) 第一部分(sizeof(a)/sizeof(*(a)))相当简单;它将整个数组的大小除以第一个元素的

好的,我不是一个完全的新手,但是我不能说我理解下面的宏。最令人困惑的部分是价值大小的划分:这到底能实现什么?特别是,因为我看到了一个否定运算符,据我所知,它可能会导致一个零值。这是否意味着它可以导致零除误差?(顺便说一句,宏是正确的,工作起来很漂亮。)

#定义数组大小(a)\
((sizeof(a)/sizeof(*(a)))/\
静态施法(!(sizeof(a)%sizeof(*(a)щщ))
第一部分
(sizeof(a)/sizeof(*(a)))
相当简单;它将整个数组的大小除以第一个元素的大小(假设您将数组类型的对象而不是指针传递给宏)。这将给出数组中的元素数

第二部分并不那么简单。我认为势能除以零是有意的;无论出于何种原因,如果数组的大小不是其某个元素的整数倍,则会导致编译时错误。换句话说,这是某种编译时的健全性检查


然而,我不知道在什么情况下会发生这种情况。。。正如人们在下面的评论中所建议的那样,它将捕获一些误用(比如在指针上使用
ARRAYSIZE()
)。不过,它不会捕获所有这样的错误。

它确实会导致被零除的错误(有意)。该宏的工作方式是将以字节为单位的数组大小除以以字节为单位的单个数组元素的大小。因此,如果您有一个
int
值的数组,其中
int
是4个字节(在大多数32位机器上),那么一个4
int
值的数组将是16个字节

因此,当您在这样的数组上调用此宏时,它会执行
sizeof(array)/sizeof(*array)
。由于16/4=4,它返回数组中有4个元素

注意:
*array
取消对数组第一个元素的引用,相当于
数组[0]

第二个除法进行模除法(得到除法的剩余部分),由于任何非零值都被视为“真”,因此使用
运算符”将导致被零除法(类似地,除1之外也会导致被零除法)。

假设我们有

T arr[42];
ARRAYSIZE(arr)
将扩展到(rougly)

在这种情况下,给出42/!0等于42


如果由于某种原因sizeof数组不能被其元素的sizeof整除,则会发生被零除的情况。什么时候能发生?例如,当您传递一个动态分配的数组而不是静态数组时

末尾的除法似乎是试图检测非数组参数(例如指针)

例如,它无法检测到
char*
,但可用于
T*
,其中
sizeof(T)
大于指针的大小

在C++中,人们通常更喜欢下面的函数模板:

typedef ptrdiff_t Size;

template< class Type, Size n >
Size countOf( Type (&)[n] ) { return n; }
免责声明:所有代码未被编译器的手触及

但一般来说,只需使用第一个函数模板,
countOf


干杯&hth.

以零为单位的div可能试图捕捉由任何原因引起的对齐错误。例如,如果在某些编译器设置下,数组元素的大小为3,但编译器会将其四舍五入以加快数组访问速度,那么由4个条目组成的数组的大小将为16和!(16/3)将变为零,在编译时除以零。但是,我不知道任何编译器都这样做,它可能违反C++的规格,以便返回一个与数组中的大小不同的大小。

来晚一点…… <>谷歌的C++ C++基础实现了 Alraysiz()/Cuth-Ge宏的权威C++实现,其中包含了一些未被考虑到的皱纹。


我无法改进,因为它有清晰完整的注释。

我编写了此宏的此版本。考虑旧版本:

#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";
}
发生什么事了?阵列大小是如何从32变为零的?问题是函数参数实际上是一个指针,尽管它看起来像一个数组。所以在foo内部,“sizeof(stats)”是8字节,“sizeof(*stats)”仍然是144字节

使用新宏:

#define ARRAYSIZE(a) \
  ((sizeof(a) / sizeof(*(a))) / \
  static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
#定义数组大小(a)\
((sizeof(a)/sizeof(*(a)))/\
静态施法(!(sizeof(a)%sizeof(*(a)щщ))
当sizeof(a)不是sizeof(*(a))的倍数时,%不是零,这是!反转,然后静态_cast的计算结果为零,导致编译时除以零。因此,在宏中,这个奇怪的划分在编译时抓住了这个问题


PS:在C++17中,只需使用std::size,请参见

我认为它是用来捕捉偶尔对宏的误用,比如在指针而不是数组上调用宏。不幸的是,它没有捕捉到像在指向与指针大小相同的对象的指针上调用它这样的事情。我能想到的主要情况是当
a
是指针时,指向的对象的大小不是
sizeof(a)
的一个因子。因此,大多数类都是这样,但如果
a
char*
,则无法得到所需的零除。有更好的方法来编写一个数组大小助手在C++中,以便得到警告/错误时,它与指针一起使用。这是C++,不是双用途C++和C,因为 StistaCase。链接现在已经死了,留下这个答案没有任何信息。死链接现在应该被固定。
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 )
#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";
}
sizeof stats = 4608
sizeof *stats = 144
ARRAYSIZE=32
sizeof stats = 8
sizeof *stats = 144
ARRAYSIZE=0
#define ARRAYSIZE(a) \
  ((sizeof(a) / sizeof(*(a))) / \
  static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))