这段代码发生了什么

What is happening with this code?

本文关键字:发生了 什么 代码 段代码      更新时间:2023-10-16

我正在尝试使用Android AOSP键盘源作为模型开发Android键盘。有相当多的JNI代码,我的c++有点生锈,我对宏NELEMS的以下定义有麻烦:

// Disclaimer: You will see a compile error if you use this macro against a variable-length array.
// Sorry for the inconvenience. It isn't supported.
template <typename T, int N>
char (&ArraySizeHelper(T (&array)[N]))[N];
#define NELEMS(x) (sizeof(ArraySizeHelper(x)))

当我尝试编译时,这段代码的第二行(就在#define上方)显示错误:

引用变量的声明需要初始化式

错误信息对我来说是有意义的;AOSP代码没有。符号ArraySizeHelper在AOSP代码或make文件中没有其他地方出现(也就是说,据我所知,它不是其他东西的宏)。

从宏的名字,我猜它应该计算数组中元素的数量。据我所知,通常的做法是:

#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))

所以我想知道这里是否发生了什么。

我希望能解释一下这段代码应该做什么,并指导一下如何处理编译错误。

EDIT:我通过Android Studio 1.3 RC 3, Android NDK r10e和Gradle 2.5进行编译。编译使用各种工具链(如本Android文档所述)。奇怪的是,上面的代码现在正确地编译和执行了(也许它总是这样)。然而,Android studio仍然在这一行显示一个错误。它还在每次使用NELEMS时显示一个错误:

宏替换后错误:参数太多,预期为0

我现在认为这是一个IDE代码分析错误,而不是编译器或编码问题。我最初的问题是关于代码本身,所以我把这个线程标记为回答。我将打开另一个似乎是IDE问题的问题。感谢大家的解释!

代码的目的是安全地获得可以在编译时使用的数组大小,例如,作为新的原始(非动态)数组的大小。

简单定义

#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))

白马王子;是不安全的,因为您可以向它传递一个指针,并返回一个无意义的大小。

你的代码,

template <typename T, int N>
char (&ArraySizeHelper(T (&array)[N]))[N];
#define NELEMS(x) (sizeof(ArraySizeHelper(x)))

白马王子;使用模板参数推导查找大小,并使用引用到数组的返回类型将大小报告为编译时常量。如果不是c++ 11中(1)的愚蠢措辞,我们现在可以对constexpr做同样的事情。唉,我们可能要等到c++ 17才能完全避免使用宏来完成获取编译时数组大小的简单任务。


我无法重现这个问题;以下代码:

template <typename T, int N>
char (&ArraySizeHelper(T (&array)[N]))[N];
#define NELEMS(x) (sizeof(ArraySizeHelper(x)))
#include <iostream>
auto main() -> int
{
    using namespace std;
    int x[42];
    cout << NELEMS( x ) << endl;
}

在Visual c++ 2015和mingw - 64g++ 5.1.0下都能很好地编译。


<一口>1) c++ 14§5.19/2 “A 条件表达式 e核心常量表达式,除非e求值,遵循[…] -一个id-expression,它指向引用类型的变量或数据成员,除非引用之前有初始化,并且两者都有-用常量表达式或初始化-它是一个对象的非静态数据成员,其生命周期开始于e;”

This:

template <typename T, int N>
char (&ArraySizeHelper(T (&array)[N]))[N];

声明了一个名为ArraySizeHelper的函数,它接受一个名为N的数组的引用,T名为array,并返回一个指向char[N]的数组的引用。没有给出定义。

sizeof()不需要定义函数——它的操作数是未求值的。它只对类型进行操作:因此,如果x的类型为T[N],则sizeof(ArrayHelper(x))的值为sizeof(char[N])(否则不会编译)。

这也是一种非常复杂的写法:

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

更容易理解。并且不需要宏