🔥作者简介: 一个平凡而乐于分享的小比特,中南民族大学通信工程专业研究生,研究方向无线联邦学习
🎬擅长领域:驱动开发,嵌入式软件开发,BSP开发
❄️作者主页:一个平凡而乐于分享的小比特的个人主页
✨收录专栏:c语言重要知识点总结,本专栏旨在总结C语言学习过程中的易错点,通过调试代码,分析原理,对重要知识点有更清晰的理解
欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖

ARRAY_SIZE宏作用及使用注意事项
ARRAY_SIZE 宏是C/C++中用于在编译时获取数组元素个数的常用宏。我来详细讲解它的原理、作用和注意事项。
1. 基本定义
c
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
2. 工作原理
示例说明
c
int arr[10];
size_t size = ARRAY_SIZE(arr); // 展开为: sizeof(arr) / sizeof(arr[0])
// = (10 * sizeof(int)) / sizeof(int)
// = 10
3. 主要作用
3.1 遍历数组更安全
c
int arr[] = {1, 2, 3, 4, 5}; // 编译器自动计算为5个元素
// 传统方式需要手动计算
for (int i = 0; i < 5; i++) { ... }
// 使用ARRAY_SIZE更安全
for (size_t i = 0; i < ARRAY_SIZE(arr); i++) {
// 自动适应数组大小变化
}
3.2 防止硬编码魔法数字
c
// 不好的写法
process_array(arr, 10);
// 好的写法
process_array(arr, ARRAY_SIZE(arr));
4. 重要注意事项
4.1 不能用于指针
c
// 错误用法示例
void bad_example(int *ptr) {
size_t size = ARRAY_SIZE(ptr); // 错误!ptr是指针,不是数组
}
void test() {
int arr[10];
int *ptr = arr;
size_t s1 = ARRAY_SIZE(arr); // 正确:10
size_t s2 = ARRAY_SIZE(ptr); // 错误:sizeof(ptr)是指针大小,不是数组大小
}
4.2 不能用于动态分配的数组
c
int *dynamic_arr = malloc(10 * sizeof(int));
size_t size = ARRAY_SIZE(dynamic_arr); // 错误!得到的是指针大小/元素大小
4.3 宏参数必须是数组类型
c
// Linux内核中的安全版本(部分实现)
#define ARRAY_SIZE(arr) \
(__builtin_types_compatible_p(typeof(arr[0])[], typeof(arr)) ? \
sizeof(arr) / sizeof((arr)[0]) : -1)
4.4 C++中的替代方案
cpp
// C++11以后可以使用模板
template<typename T, size_t N>
constexpr size_t array_size(T (&)[N]) { return N; }
// 或者使用std::array
#include <array>
std::array<int, 5> arr;
size_t size = arr.size();
5. 实际应用场景
5.1 初始化数组
c
const char *days[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
const size_t days_count = ARRAY_SIZE(days); // 自动得到7
5.2 安全的内存操作
c
int src[100];
int dest[ARRAY_SIZE(src)]; // 确保目标数组足够大
memcpy(dest, src, sizeof(src));
5.3 结构体数组处理
c
struct Student {
int id;
char name[20];
};
struct Student students[50];
size_t student_count = ARRAY_SIZE(students);
6. 高级技巧
6.1 编译时断言
c
// 确保数组大小符合预期
#define STATIC_ASSERT_ARRAY_SIZE(arr, expected) \
static_assert(ARRAY_SIZE(arr) == expected, "Array size mismatch")
int my_array[10];
STATIC_ASSERT_ARRAY_SIZE(my_array, 10); // 编译时检查
6.2 安全遍历
c
#define FOREACH_ARRAY(item, arr) \
for (size_t i = 0, _count = ARRAY_SIZE(arr); i < _count && (item = &arr[i], 1); i++)
int arr[] = {1, 2, 3, 4, 5};
FOREACH_ARRAY(int *item, arr) {
printf("%d\n", *item);
}
7. 常见错误总结
-
误用于指针:最常见的错误
-
在函数参数中使用 :数组参数会退化为指针
cvoid func(int arr[]) { size_t size = ARRAY_SIZE(arr); // 错误!arr是指针 } -
忘记包含必要的头文件 :
sizeof需要知道类型大小 -
混合使用C和C++:C++有更好的替代方案
8. 最佳实践建议
-
在宏定义前后加括号:
c#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) -
使用size_t类型存储结果:
csize_t count = ARRAY_SIZE(arr); // 正确 int count = ARRAY_SIZE(arr); // 可能丢失精度 -
考虑使用更安全的变体:
c// GNU扩展版本 #define ARRAY_SIZE(arr) \ (sizeof(arr) / sizeof((arr)[0]) + \ sizeof(typeof(int[1 - 2 * !!__builtin_types_compatible_p(typeof(arr), typeof(&arr[0]))])) * 0) -
明确文档说明:在团队代码中注明宏的限制
总结
ARRAY_SIZE是一个简单但强大的宏,正确使用时能显著提高代码的安全性和可维护性。关键是记住它的核心限制 :只能用于真正的数组,不能用于指针。在C++中,考虑使用类型安全的替代方案。