首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >ARRAY_SIZE宏作用及使用注意事项

ARRAY_SIZE宏作用及使用注意事项

作者头像
一个平凡而乐于分享的小比特
发布2026-02-02 17:20:20
发布2026-02-02 17:20:20
760
举报

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

在这里插入图片描述
在这里插入图片描述

ARRAY_SIZE宏作用及使用注意事项

ARRAY_SIZE 宏是C/C++中用于在编译时获取数组元素个数的常用宏。我来详细讲解它的原理、作用和注意事项。

1. 基本定义

代码语言:javascript
复制
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

2. 工作原理

示例说明
代码语言:javascript
复制
int arr[10];
size_t size = ARRAY_SIZE(arr);  // 展开为: sizeof(arr) / sizeof(arr[0])
                               // = (10 * sizeof(int)) / sizeof(int)
                               // = 10

3. 主要作用

3.1 遍历数组更安全
代码语言:javascript
复制
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 防止硬编码魔法数字
代码语言:javascript
复制
// 不好的写法
process_array(arr, 10);

// 好的写法
process_array(arr, ARRAY_SIZE(arr));

4. 重要注意事项

4.1 不能用于指针
代码语言:javascript
复制
// 错误用法示例
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 不能用于动态分配的数组
代码语言:javascript
复制
int *dynamic_arr = malloc(10 * sizeof(int));
size_t size = ARRAY_SIZE(dynamic_arr);  // 错误!得到的是指针大小/元素大小
4.3 宏参数必须是数组类型
代码语言:javascript
复制
// Linux内核中的安全版本(部分实现)
#define ARRAY_SIZE(arr) \
    (__builtin_types_compatible_p(typeof(arr[0])[], typeof(arr)) ? \
     sizeof(arr) / sizeof((arr)[0]) : -1)
4.4 C++中的替代方案
代码语言:javascript
复制
// 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 初始化数组
代码语言:javascript
复制
const char *days[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
const size_t days_count = ARRAY_SIZE(days);  // 自动得到7
5.2 安全的内存操作
代码语言:javascript
复制
int src[100];
int dest[ARRAY_SIZE(src)];  // 确保目标数组足够大
memcpy(dest, src, sizeof(src));
5.3 结构体数组处理
代码语言:javascript
复制
struct Student {
    int id;
    char name[20];
};

struct Student students[50];
size_t student_count = ARRAY_SIZE(students);

6. 高级技巧

6.1 编译时断言
代码语言:javascript
复制
// 确保数组大小符合预期
#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 安全遍历
代码语言:javascript
复制
#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. 常见错误总结

误用于指针:最常见的错误

在函数参数中使用:数组参数会退化为指针

代码语言:javascript
复制
void func(int arr[]) {
    size_t size = ARRAY_SIZE(arr);  // 错误!arr是指针
}

忘记包含必要的头文件sizeof需要知道类型大小

混合使用C和C++:C++有更好的替代方案

8. 最佳实践建议

在宏定义前后加括号

代码语言:javascript
复制
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

使用size_t类型存储结果

代码语言:javascript
复制
size_t count = ARRAY_SIZE(arr);  // 正确
int count = ARRAY_SIZE(arr);     // 可能丢失精度

考虑使用更安全的变体

代码语言:javascript
复制
// 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++中,考虑使用类型安全的替代方案。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2026-01-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ARRAY_SIZE宏作用及使用注意事项
    • 1. 基本定义
    • 2. 工作原理
      • 示例说明
    • 3. 主要作用
      • 3.1 遍历数组更安全
      • 3.2 防止硬编码魔法数字
    • 4. 重要注意事项
      • 4.1 不能用于指针
      • 4.2 不能用于动态分配的数组
      • 4.3 宏参数必须是数组类型
      • 4.4 C++中的替代方案
    • 5. 实际应用场景
      • 5.1 初始化数组
      • 5.2 安全的内存操作
      • 5.3 结构体数组处理
    • 6. 高级技巧
      • 6.1 编译时断言
      • 6.2 安全遍历
    • 7. 常见错误总结
    • 8. 最佳实践建议
    • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档