经常教授的标准数组大小的宏是
#define ARRAYSIZE(arr) (sizeof(arr) / sizeof(arr[0]))
Run Code Online (Sandbox Code Playgroud)
或一些等效的形成.然而,当传入指针时,这种事情会默默地成功,并且在运行时看起来似乎有道理,直到事情神秘地分崩离析.
犯这个错误太容易了:一个具有局部数组变量的函数被重构,将一些数组操作移动到一个以数组作为参数调用的新函数中.
所以,问题是:是否有一个"卫生"宏来检测ARRAYSIZEC中宏的滥用,最好是在编译时?在C++中,我们只使用专门用于数组参数的模板; 在C中,似乎我们需要一些方法来区分数组和指针.(例如,如果我想拒绝数组,我只是(arr=arr, ...)因为数组赋值是非法的).
以下程序在gcc 4.8.2上两次打印相同的数字:
#include <stdio.h>
int main()
{
char a[13];
printf("sizeof a is %zu\n", sizeof a );
printf("sizeof(a) is %zu\n", sizeof(a));
}
Run Code Online (Sandbox Code Playgroud)
根据这篇reddit帖子,gcc在这方面并不符合标准,因为当数组到指针衰减没有发生时,括号表达式不在异常列表中.
这家伙是对的吗?这是相关的标准报价:
除非它是运算
sizeof符或一元运算&符的操作数,或者是用于初始化字符数组数组的字符串文字,或者是用于初始化与元素类型兼容的数组的宽字符串文字,否则具有wchar_t的左值类型'array of type'被转换为一个表达式,其类型为'指向类型的指针',指向数组对象的初始成员而不是左值.
为了清楚起见,他认为(a)应该触发数组到指针的衰减,因为上面的列表中没有括号括起来(sizeof运算符,一元运算&符,字符串文字作为初始值).
在C中获取数组元素的通常方法是这样的:
#define COUNTOF(arr) (sizeof(arr) / sizeof(arr[0]))
Run Code Online (Sandbox Code Playgroud)
这导致了一个整数常量表达式,这也是一个非常好的加法.
问题是它不是类型安全的:int* i; COUNTOF(i); /* compiles :( */.在实践中,这应该很少出现,但为了正确起见,使这种类型安全是很好的.
在C++ 03中这很容易(在C++ 11中它更容易,留给读者练习):
template <typename T, std::size_t N>
char (&countof_detail(T (&)[N]))[N]; // not defined
#define COUNTOF(arr) (sizeof(countof_detail(arr)))
Run Code Online (Sandbox Code Playgroud)
这使用模板推导来获取N数组的大小,然后将其编码为类型的大小.
但是在C中我们没有得到那种语言功能.这是我做的小框架:
// if `condition` evaluates to 0, fails to compile; otherwise results in `value`
#define STATIC_ASSERT_EXPR(condition, value) \
(sizeof(char[(condition) ? 1 : -1]), (value))
// usual type-unsafe method
#define COUNTOF_DETAIL(arr) (sizeof(arr) / sizeof(arr[0]))
// new method:
#define COUNTOF(arr) \
STATIC_ASSERT_EXPR(/* ??? */, \
COUNTOF_DETAIL(arr)) …Run Code Online (Sandbox Code Playgroud) 我一直在寻找有趣且优选有用的C宏/定义示例,它们比定义consts或min/max函数更广泛.我的理解是,宏应该允许某种程度的元编程(尽管我并不完全确定),但是搜索未能揭示太多,因此非常感谢使用宏进行元编程的示例,或解释为什么它不能工作.总的来说,我对任何"酷"的宏用途感兴趣.
PS我明白这个问题很快就会"没有建设性和关闭性",但我认为它至少可以成为一个有趣的社区维基问题.
编辑:我对C++,任何东西都不感兴趣.
可以使用*(&arr+1)-arr该数据计算数组长度,然后简化(&arr)[1]-arr进一步简化为的数组长度1[&arr]-arr.
但是,当在与已完成内存分配的函数中计算长度时,计算错误的结果.
例如,
#include <iostream>
#define ARRAY_SIZE(arr) (1[&arr]-arr)
using namespace std;
void func(int *arr)
{
cout<<ARRAY_SIZE(arr)<<endl;
}
int main()
{
int arr[]={1,2,3,4,5};
cout<<ARRAY_SIZE(arr)<<endl;
func(arr);
}
Run Code Online (Sandbox Code Playgroud)
这给出了输出:
5
8
Run Code Online (Sandbox Code Playgroud)
是什么导致了这种奇怪的行为?