C语言数组参数传递的三种写法从困惑到精通一、问题的核心数组参数传递的本质在C语言中当数组作为函数参数时它不会像普通变量那样被复制传递。实际上数组名在大多数情况下会退化为指针。这就是为什么你看到这三种写法实际上是等效的。核心概念数组名退化为指针// 定义数组uint8_tmode_array[4]{1,2,1,2};// 数组名在大多数表达式中会退化为指向第一个元素的指针// mode_array 等价于 mode_array[0]二、三种写法的深度解析1.带数组大小的形式// 写法1带数组大小的形式HAL_StatusTypeDefdac53204_set_mode(uint8_tmode[DAC53204_CHANNEL]){// 函数内部可以像使用数组一样使用modefor(inti0;iDAC53204_CHANNEL;i){printf(mode[%d] %d\n,i,mode[i]);}returnHAL_OK;}特点分析语法糖看起来像是传递整个数组但实际上仍然是指针文档作用明确告诉调用者期望的数组大小编译器行为编译器会忽略中括号内的数字只作为提示常见误区很多人以为这里会进行数组边界检查但实际上不会验证代码#includestdio.hvoidtest_array_size(intarr[5]){// 尝试获取数组大小printf(sizeof(arr) in function: %lu\n,sizeof(arr));// 输出864位系统指针大小不是205 * sizeof(int))// 证明arr实际上是指针}intmain(){intarr[5]{1,2,3,4,5};printf(sizeof(arr) in main: %lu\n,sizeof(arr));// 输出20test_array_size(arr);return0;}2.带空括号的形式// 写法2带空括号的形式HAL_StatusTypeDefdac53204_set_mode(uint8_tmode[]){// 和写法1完全等价// 编译后没有任何区别returnHAL_OK;}特点分析最原始的数组参数语法明确表示这是一个数组但大小未知需要额外信息通常需要另一个参数传递数组大小或者依赖全局常量向后兼容早期的C代码常用这种写法使用场景示例// 需要传递数组大小的例子voidprocess_array(intarr[],intsize){for(inti0;isize;i){arr[i]*2;}}// 或者使用全局常量#defineARRAY_SIZE10voidprocess_fixed_array(intarr[]){for(inti0;iARRAY_SIZE;i){// 处理arr[i]}}3.指针形式最本质的形式// 写法3指针形式最本质的形式HAL_StatusTypeDefdac53204_set_mode(uint8_t*mode){// 这是数组参数传递的底层真相returnHAL_OK;}特点分析揭示本质直接表明参数是指针灵活性可以指向单个变量也可以指向数组清晰明确没有语法糖直接展示工作原理通用性适用于任何需要传递地址的情况指针与数组下标的关系// 以下三种访问方式是等价的voidexample(uint8_t*arr){uint8_tvalue1arr[2];// 数组下标法uint8_tvalue2*(arr2);// 指针偏移法uint8_tvalue3*(2arr);// 另一种写法很少用// arr[i] 在编译时被转换为 *(arr i)// 这就是为什么 arr[i] 和 i[arr] 都能工作的原因uint8_tvalue42[arr];// 合法的但不推荐}三、回到你的具体函数dac53204_set_mode函数原理解析HAL_StatusTypeDefdac53204_set_mode(uint8_tmode[DAC53204_CHANNEL]){HAL_StatusTypeDef ret;uint8_ti;uint16_ttemp0xfff;// 二进制1111 1111 1111for(i0;iDAC53204_CHANNEL;i){if(mode[i]1)temp~(1(3*i));// 清除特定位置elseif(mode[i]2){temp~(3(3*i1));// 清除两个连续位}}returndac53204_update_bits(DAC53204_REG_COMMON_CONFIG,0xfff,temp);}参数mode数组的解读假设DAC53204_CHANNEL 4那么这个函数期望一个包含4个元素的数组// 示例设置4个通道的模式uint8_tchannel_modes[4]{1,2,1,2};dac53204_set_mode(channel_modes);// 或者直接传递数组字面量dac53204_set_mode((uint8_t[]){1,2,1,2});位操作逻辑分析让我们详细分析这个函数的位操作// 假设 DAC53204_CHANNEL 4// temp初始值: 0xfff 1111 1111 1111 (二进制)// 每个通道占用3个比特位// 通道0: 位[2:0]// 通道1: 位[5:3]// 通道2: 位[8:6]// 通道3: 位[11:9]// 当 mode[i] 1 时//清除位 (3 * i)// 即每个通道的最低有效位//例如 i0: 清除位0//i1: 清除位3//i2: 清除位6//i3: 清除位9// 当 mode[i] 2 时//清除位 (3 * i 1) 和 (3 * i 2)// 即两个较高位//使用 3 (3 * i 1) 创建掩码//例如 i0: 清除位1和位2//i1: 清除位4和位5//i2: 清除位7和位8//i3: 清除位10和位11四、为什么三种写法都有效编译器的视角// 从编译器角度看这三种写法被处理成相同的中间表示// 源代码voidfunc1(intarr[10]);voidfunc2(intarr[]);voidfunc3(int*arr);// 编译后都等价于voidfunc(int*arr);// 证明查看反汇编// 无论哪种写法函数调用时传递的都是数组首地址实际测试代码#includestdio.h#includestdint.h#defineCHANNEL_COUNT4// 三种不同写法的函数声明voidtest_method1(uint8_tarr[CHANNEL_COUNT]);voidtest_method2(uint8_tarr[]);voidtest_method3(uint8_t*arr);// 但它们有相同的实现voidtest_method1(uint8_tarr[CHANNEL_COUNT]){printf(Method1: );for(inti0;iCHANNEL_COUNT;i){printf(%d ,arr[i]);}printf(\n);}voidtest_method2(uint8_tarr[]){printf(Method2: );for(inti0;iCHANNEL_COUNT;i){printf(%d ,arr[i]);}printf(\n);}voidtest_method3(uint8_t*arr){printf(Method3: );for(inti0;iCHANNEL_COUNT;i){printf(%d ,arr[i]);}printf(\n);}// 验证函数指针兼容性intmain(){uint8_tdata[CHANNEL_COUNT]{1,2,3,4};// 所有调用方式都有效test_method1(data);test_method2(data);test_method3(data);// 函数指针测试void(*func_ptr1)(uint8_t[CHANNEL_COUNT])test_method1;void(*func_ptr2)(uint8_t[])test_method2;void(*func_ptr3)(uint8_t*)test_method3;// 这些函数指针可以互相赋值证明函数类型相同func_ptr1test_method3;// 有效func_ptr2test_method1;// 有效func_ptr3test_method2;// 有效return0;}五、最佳实践建议1.何时使用哪种写法推荐写法1带数组大小// 当数组大小是固定的且是API的一部分时#defineMAX_BUFFER_SIZE256// 明确告诉使用者需要多大数组voidprocess_buffer(uint8_tbuffer[MAX_BUFFER_SIZE]){// 函数内部可以使用MAX_BUFFER_SIZEfor(inti0;iMAX_BUFFER_SIZE;i){// 处理buffer[i]}}推荐写法2空括号// 当数组大小可变需要额外参数传递大小时voidprocess_data(uint8_tdata[],intdata_size){for(inti0;idata_size;i){// 处理data[i]}}推荐写法3指针形式// 当需要明确表示处理的是内存块时// 或者需要处理单个变量和数组的通用情况voidcopy_memory(uint8_t*dest,constuint8_t*src,size_tsize){memcpy(dest,src,size);}// 或者当函数需要修改指针本身时voidallocate_and_init(int**ptr,intsize){*ptrmalloc(size*sizeof(int));// 初始化...}2.你的DAC53204函数改进建议// 原函数有潜在问题只处理mode[i]为1或2的情况// 其他值会被忽略这可能是bug// 改进版本1添加默认处理HAL_StatusTypeDefdac53204_set_mode_improved(uint8_tmode[DAC53204_CHANNEL]){uint16_ttemp0xfff;for(uint8_ti0;iDAC53204_CHANNEL;i){switch(mode[i]){case0:// 模式0不清除任何位break;case1:// 模式1清除位(3*i)temp~(1(3*i));break;case2:// 模式2清除位(3*i1)和(3*i2)temp~(3(3*i1));break;default:// 处理错误或使用默认值returnHAL_ERROR;}}returndac53204_update_bits(DAC53204_REG_COMMON_CONFIG,0xfff,temp);}// 改进版本2使用结构体提高可读性typedefstruct{uint8_tchannel0_mode:2;// 使用位域uint8_tchannel1_mode:2;uint8_tchannel2_mode:2;uint8_tchannel3_mode:2;}dac53204_mode_config_t;HAL_StatusTypeDefdac53204_set_mode_struct(constdac53204_mode_config_t*config){uint16_ttemp0xfff;// 通道0if(config-channel0_mode1)temp~(10);elseif(config-channel0_mode2)temp~(31);// 通道1if(config-channel1_mode1)temp~(13);elseif(config-channel1_mode2)temp~(34);// 通道2if(config-channel2_mode1)temp~(16);elseif(config-channel2_mode2)temp~(37);// 通道3if(config-channel3_mode1)temp~(19);elseif(config-channel3_mode2)temp~(310);returndac53204_update_bits(DAC53204_REG_COMMON_CONFIG,0xfff,temp);}六、常见误区与陷阱1.sizeof陷阱voidwrong_sizeof_example(intarr[10]){// 错误这里sizeof(arr)返回的是指针大小不是数组大小intsizesizeof(arr)/sizeof(arr[0]);// 错误// 在64位系统上sizeof(arr)8, sizeof(arr[0])4, size2完全错误}voidcorrect_approach(intarr[],intsize){// 正确通过参数传递大小for(inti0;isize;i){// 处理arr[i]}}2.多维数组的不同行为// 一维数组三种写法等价voidfunc1d(intarr[]);// 等价于 int *arr// 二维数组行为不同voidfunc2d_wrong(intarr[][]);// 错误必须指定第二维大小voidfunc2d_correct(intarr[][10]);// 正确voidfunc2d_pointer(int(*arr)[10]);// 正确指向数组的指针// 三维数组voidfunc3d(intarr[][10][20]);// 必须指定第二维和第三维3.const正确性// 如果函数不应该修改数组内容使用constvoidread_only(constuint8_tdata[],intsize){// data[i] 10;// 编译错误不能修改const数据}// 多层const保护voidprocess_matrix(constint(*matrix)[10],introws){// matrix[0][0] 5;// 编译错误// 但可以读取intvaluematrix[0][0];}七、实际工程中的应用嵌入式系统中的典型用法// 在嵌入式开发中常见模式// 1. 配置结构体数组typedefstruct{uint32_treg_addr;uint32_treg_value;uint8_toperation;// 0只读1只写2读写}register_config_t;// 使用数组传递初始化配置voiddevice_init(constregister_config_tconfig[],intconfig_count){for(inti0;iconfig_count;i){if(config[i].operation0x01){// 写操作write_register(config[i].reg_addr,config[i].reg_value);}if(config[i].operation0x02){// 读操作uint32_tvalueread_register(config[i].reg_addr);// 验证或处理读取的值}}}// 2. DMA传输数据voidstart_dma_transfer(uint8_t*src_buffer,uint8_t*dst_buffer,uint32_tsize){// 配置DMA源地址、目标地址、数据大小dma_config.src_addr(uint32_t)src_buffer;dma_config.dst_addr(uint32_t)dst_buffer;dma_config.sizesize;// 启动DMAHAL_DMA_Start(hdma,src_buffer,dst_buffer,size);}// 3. 传感器数据采集#defineSENSOR_COUNT8voidread_sensors(uint16_tsensor_values[SENSOR_COUNT]){for(inti0;iSENSOR_COUNT;i){sensor_values[i]read_sensor(i);}}你的DAC53204函数在系统中的使用// 系统初始化时配置DACvoidsystem_dac_init(void){// 方法1使用数组uint8_tdac_modes[DAC53204_CHANNEL]{1,// 通道0模式12,// 通道1模式21,// 通道2模式12// 通道3模式2};dac53204_set_mode(dac_modes);// 方法2动态配置uint8_tdynamic_modes[DAC53204_CHANNEL];for(inti0;iDAC53204_CHANNEL;i){dynamic_modes[i]get_channel_mode_from_config(i);}dac53204_set_mode(dynamic_modes);// 方法3直接传递数组字面量C99特性dac53204_set_mode((uint8_t[]){1,2,1,2});}八、总结关键要点数组参数传递的本质是指针传递三种写法在编译后完全相同写法1type name[size]提供文档信息提示调用者数组期望大小写法2type name[]传统写法表示数组但大小未知写法3type *name最本质的写法明确表达指针语义永远记住在函数内部sizeof(数组参数)返回的是指针大小选择建议嵌入式/硬件驱动开发推荐使用写法1明确硬件要求通用库开发推荐使用写法3最灵活维护旧代码保持原有风格新项目根据团队规范选择保持一致性最后验证// 最终验证三种写法真的等价吗// 答案是在函数声明/定义时三种写法完全等价// 但在函数指针类型声明时有微妙差异typedefvoid(*FuncType1)(int[10]);// 指向接受int[10]的函数的指针typedefvoid(*FuncType2)(int[]);// 指向接受int[]的函数的指针typedefvoid(*FuncType3)(int*);// 指向接受int*的函数的指针// 但实际上这些函数指针类型之间可以互相转换// 因为它们指向的函数在机器码层面完全相同理解了数组参数传递的本质你就能看懂90%的C语言嵌入式代码了。记住数组作为函数参数时传递的是指针不是整个数组。这是C语言中最重要的概念之一也是很多初学者困惑的根源。
C语言数组参数传递的三种写法:从困惑到精通
C语言数组参数传递的三种写法从困惑到精通一、问题的核心数组参数传递的本质在C语言中当数组作为函数参数时它不会像普通变量那样被复制传递。实际上数组名在大多数情况下会退化为指针。这就是为什么你看到这三种写法实际上是等效的。核心概念数组名退化为指针// 定义数组uint8_tmode_array[4]{1,2,1,2};// 数组名在大多数表达式中会退化为指向第一个元素的指针// mode_array 等价于 mode_array[0]二、三种写法的深度解析1.带数组大小的形式// 写法1带数组大小的形式HAL_StatusTypeDefdac53204_set_mode(uint8_tmode[DAC53204_CHANNEL]){// 函数内部可以像使用数组一样使用modefor(inti0;iDAC53204_CHANNEL;i){printf(mode[%d] %d\n,i,mode[i]);}returnHAL_OK;}特点分析语法糖看起来像是传递整个数组但实际上仍然是指针文档作用明确告诉调用者期望的数组大小编译器行为编译器会忽略中括号内的数字只作为提示常见误区很多人以为这里会进行数组边界检查但实际上不会验证代码#includestdio.hvoidtest_array_size(intarr[5]){// 尝试获取数组大小printf(sizeof(arr) in function: %lu\n,sizeof(arr));// 输出864位系统指针大小不是205 * sizeof(int))// 证明arr实际上是指针}intmain(){intarr[5]{1,2,3,4,5};printf(sizeof(arr) in main: %lu\n,sizeof(arr));// 输出20test_array_size(arr);return0;}2.带空括号的形式// 写法2带空括号的形式HAL_StatusTypeDefdac53204_set_mode(uint8_tmode[]){// 和写法1完全等价// 编译后没有任何区别returnHAL_OK;}特点分析最原始的数组参数语法明确表示这是一个数组但大小未知需要额外信息通常需要另一个参数传递数组大小或者依赖全局常量向后兼容早期的C代码常用这种写法使用场景示例// 需要传递数组大小的例子voidprocess_array(intarr[],intsize){for(inti0;isize;i){arr[i]*2;}}// 或者使用全局常量#defineARRAY_SIZE10voidprocess_fixed_array(intarr[]){for(inti0;iARRAY_SIZE;i){// 处理arr[i]}}3.指针形式最本质的形式// 写法3指针形式最本质的形式HAL_StatusTypeDefdac53204_set_mode(uint8_t*mode){// 这是数组参数传递的底层真相returnHAL_OK;}特点分析揭示本质直接表明参数是指针灵活性可以指向单个变量也可以指向数组清晰明确没有语法糖直接展示工作原理通用性适用于任何需要传递地址的情况指针与数组下标的关系// 以下三种访问方式是等价的voidexample(uint8_t*arr){uint8_tvalue1arr[2];// 数组下标法uint8_tvalue2*(arr2);// 指针偏移法uint8_tvalue3*(2arr);// 另一种写法很少用// arr[i] 在编译时被转换为 *(arr i)// 这就是为什么 arr[i] 和 i[arr] 都能工作的原因uint8_tvalue42[arr];// 合法的但不推荐}三、回到你的具体函数dac53204_set_mode函数原理解析HAL_StatusTypeDefdac53204_set_mode(uint8_tmode[DAC53204_CHANNEL]){HAL_StatusTypeDef ret;uint8_ti;uint16_ttemp0xfff;// 二进制1111 1111 1111for(i0;iDAC53204_CHANNEL;i){if(mode[i]1)temp~(1(3*i));// 清除特定位置elseif(mode[i]2){temp~(3(3*i1));// 清除两个连续位}}returndac53204_update_bits(DAC53204_REG_COMMON_CONFIG,0xfff,temp);}参数mode数组的解读假设DAC53204_CHANNEL 4那么这个函数期望一个包含4个元素的数组// 示例设置4个通道的模式uint8_tchannel_modes[4]{1,2,1,2};dac53204_set_mode(channel_modes);// 或者直接传递数组字面量dac53204_set_mode((uint8_t[]){1,2,1,2});位操作逻辑分析让我们详细分析这个函数的位操作// 假设 DAC53204_CHANNEL 4// temp初始值: 0xfff 1111 1111 1111 (二进制)// 每个通道占用3个比特位// 通道0: 位[2:0]// 通道1: 位[5:3]// 通道2: 位[8:6]// 通道3: 位[11:9]// 当 mode[i] 1 时//清除位 (3 * i)// 即每个通道的最低有效位//例如 i0: 清除位0//i1: 清除位3//i2: 清除位6//i3: 清除位9// 当 mode[i] 2 时//清除位 (3 * i 1) 和 (3 * i 2)// 即两个较高位//使用 3 (3 * i 1) 创建掩码//例如 i0: 清除位1和位2//i1: 清除位4和位5//i2: 清除位7和位8//i3: 清除位10和位11四、为什么三种写法都有效编译器的视角// 从编译器角度看这三种写法被处理成相同的中间表示// 源代码voidfunc1(intarr[10]);voidfunc2(intarr[]);voidfunc3(int*arr);// 编译后都等价于voidfunc(int*arr);// 证明查看反汇编// 无论哪种写法函数调用时传递的都是数组首地址实际测试代码#includestdio.h#includestdint.h#defineCHANNEL_COUNT4// 三种不同写法的函数声明voidtest_method1(uint8_tarr[CHANNEL_COUNT]);voidtest_method2(uint8_tarr[]);voidtest_method3(uint8_t*arr);// 但它们有相同的实现voidtest_method1(uint8_tarr[CHANNEL_COUNT]){printf(Method1: );for(inti0;iCHANNEL_COUNT;i){printf(%d ,arr[i]);}printf(\n);}voidtest_method2(uint8_tarr[]){printf(Method2: );for(inti0;iCHANNEL_COUNT;i){printf(%d ,arr[i]);}printf(\n);}voidtest_method3(uint8_t*arr){printf(Method3: );for(inti0;iCHANNEL_COUNT;i){printf(%d ,arr[i]);}printf(\n);}// 验证函数指针兼容性intmain(){uint8_tdata[CHANNEL_COUNT]{1,2,3,4};// 所有调用方式都有效test_method1(data);test_method2(data);test_method3(data);// 函数指针测试void(*func_ptr1)(uint8_t[CHANNEL_COUNT])test_method1;void(*func_ptr2)(uint8_t[])test_method2;void(*func_ptr3)(uint8_t*)test_method3;// 这些函数指针可以互相赋值证明函数类型相同func_ptr1test_method3;// 有效func_ptr2test_method1;// 有效func_ptr3test_method2;// 有效return0;}五、最佳实践建议1.何时使用哪种写法推荐写法1带数组大小// 当数组大小是固定的且是API的一部分时#defineMAX_BUFFER_SIZE256// 明确告诉使用者需要多大数组voidprocess_buffer(uint8_tbuffer[MAX_BUFFER_SIZE]){// 函数内部可以使用MAX_BUFFER_SIZEfor(inti0;iMAX_BUFFER_SIZE;i){// 处理buffer[i]}}推荐写法2空括号// 当数组大小可变需要额外参数传递大小时voidprocess_data(uint8_tdata[],intdata_size){for(inti0;idata_size;i){// 处理data[i]}}推荐写法3指针形式// 当需要明确表示处理的是内存块时// 或者需要处理单个变量和数组的通用情况voidcopy_memory(uint8_t*dest,constuint8_t*src,size_tsize){memcpy(dest,src,size);}// 或者当函数需要修改指针本身时voidallocate_and_init(int**ptr,intsize){*ptrmalloc(size*sizeof(int));// 初始化...}2.你的DAC53204函数改进建议// 原函数有潜在问题只处理mode[i]为1或2的情况// 其他值会被忽略这可能是bug// 改进版本1添加默认处理HAL_StatusTypeDefdac53204_set_mode_improved(uint8_tmode[DAC53204_CHANNEL]){uint16_ttemp0xfff;for(uint8_ti0;iDAC53204_CHANNEL;i){switch(mode[i]){case0:// 模式0不清除任何位break;case1:// 模式1清除位(3*i)temp~(1(3*i));break;case2:// 模式2清除位(3*i1)和(3*i2)temp~(3(3*i1));break;default:// 处理错误或使用默认值returnHAL_ERROR;}}returndac53204_update_bits(DAC53204_REG_COMMON_CONFIG,0xfff,temp);}// 改进版本2使用结构体提高可读性typedefstruct{uint8_tchannel0_mode:2;// 使用位域uint8_tchannel1_mode:2;uint8_tchannel2_mode:2;uint8_tchannel3_mode:2;}dac53204_mode_config_t;HAL_StatusTypeDefdac53204_set_mode_struct(constdac53204_mode_config_t*config){uint16_ttemp0xfff;// 通道0if(config-channel0_mode1)temp~(10);elseif(config-channel0_mode2)temp~(31);// 通道1if(config-channel1_mode1)temp~(13);elseif(config-channel1_mode2)temp~(34);// 通道2if(config-channel2_mode1)temp~(16);elseif(config-channel2_mode2)temp~(37);// 通道3if(config-channel3_mode1)temp~(19);elseif(config-channel3_mode2)temp~(310);returndac53204_update_bits(DAC53204_REG_COMMON_CONFIG,0xfff,temp);}六、常见误区与陷阱1.sizeof陷阱voidwrong_sizeof_example(intarr[10]){// 错误这里sizeof(arr)返回的是指针大小不是数组大小intsizesizeof(arr)/sizeof(arr[0]);// 错误// 在64位系统上sizeof(arr)8, sizeof(arr[0])4, size2完全错误}voidcorrect_approach(intarr[],intsize){// 正确通过参数传递大小for(inti0;isize;i){// 处理arr[i]}}2.多维数组的不同行为// 一维数组三种写法等价voidfunc1d(intarr[]);// 等价于 int *arr// 二维数组行为不同voidfunc2d_wrong(intarr[][]);// 错误必须指定第二维大小voidfunc2d_correct(intarr[][10]);// 正确voidfunc2d_pointer(int(*arr)[10]);// 正确指向数组的指针// 三维数组voidfunc3d(intarr[][10][20]);// 必须指定第二维和第三维3.const正确性// 如果函数不应该修改数组内容使用constvoidread_only(constuint8_tdata[],intsize){// data[i] 10;// 编译错误不能修改const数据}// 多层const保护voidprocess_matrix(constint(*matrix)[10],introws){// matrix[0][0] 5;// 编译错误// 但可以读取intvaluematrix[0][0];}七、实际工程中的应用嵌入式系统中的典型用法// 在嵌入式开发中常见模式// 1. 配置结构体数组typedefstruct{uint32_treg_addr;uint32_treg_value;uint8_toperation;// 0只读1只写2读写}register_config_t;// 使用数组传递初始化配置voiddevice_init(constregister_config_tconfig[],intconfig_count){for(inti0;iconfig_count;i){if(config[i].operation0x01){// 写操作write_register(config[i].reg_addr,config[i].reg_value);}if(config[i].operation0x02){// 读操作uint32_tvalueread_register(config[i].reg_addr);// 验证或处理读取的值}}}// 2. DMA传输数据voidstart_dma_transfer(uint8_t*src_buffer,uint8_t*dst_buffer,uint32_tsize){// 配置DMA源地址、目标地址、数据大小dma_config.src_addr(uint32_t)src_buffer;dma_config.dst_addr(uint32_t)dst_buffer;dma_config.sizesize;// 启动DMAHAL_DMA_Start(hdma,src_buffer,dst_buffer,size);}// 3. 传感器数据采集#defineSENSOR_COUNT8voidread_sensors(uint16_tsensor_values[SENSOR_COUNT]){for(inti0;iSENSOR_COUNT;i){sensor_values[i]read_sensor(i);}}你的DAC53204函数在系统中的使用// 系统初始化时配置DACvoidsystem_dac_init(void){// 方法1使用数组uint8_tdac_modes[DAC53204_CHANNEL]{1,// 通道0模式12,// 通道1模式21,// 通道2模式12// 通道3模式2};dac53204_set_mode(dac_modes);// 方法2动态配置uint8_tdynamic_modes[DAC53204_CHANNEL];for(inti0;iDAC53204_CHANNEL;i){dynamic_modes[i]get_channel_mode_from_config(i);}dac53204_set_mode(dynamic_modes);// 方法3直接传递数组字面量C99特性dac53204_set_mode((uint8_t[]){1,2,1,2});}八、总结关键要点数组参数传递的本质是指针传递三种写法在编译后完全相同写法1type name[size]提供文档信息提示调用者数组期望大小写法2type name[]传统写法表示数组但大小未知写法3type *name最本质的写法明确表达指针语义永远记住在函数内部sizeof(数组参数)返回的是指针大小选择建议嵌入式/硬件驱动开发推荐使用写法1明确硬件要求通用库开发推荐使用写法3最灵活维护旧代码保持原有风格新项目根据团队规范选择保持一致性最后验证// 最终验证三种写法真的等价吗// 答案是在函数声明/定义时三种写法完全等价// 但在函数指针类型声明时有微妙差异typedefvoid(*FuncType1)(int[10]);// 指向接受int[10]的函数的指针typedefvoid(*FuncType2)(int[]);// 指向接受int[]的函数的指针typedefvoid(*FuncType3)(int*);// 指向接受int*的函数的指针// 但实际上这些函数指针类型之间可以互相转换// 因为它们指向的函数在机器码层面完全相同理解了数组参数传递的本质你就能看懂90%的C语言嵌入式代码了。记住数组作为函数参数时传递的是指针不是整个数组。这是C语言中最重要的概念之一也是很多初学者困惑的根源。