C语言运行时按类型解引用指针:修复代码1及优化方案
SPI多位数写函数的问题修复与优化方案
代码1的问题根源
代码1无法正常工作的核心原因是变量作用域问题:每个case块内定义的dt指针(如uint8_t* dt)仅在当前case的范围内有效,switch语句结束后这些指针已经超出作用域,后续的for循环根本无法访问dt,编译器会直接报错未定义标识符。
代码1的修复方案
把指针步长和类型信息提取到switch外部,在for循环中根据数据类型完成解引用和指针递增:
typedef enum { bits_8, bits_16, bits_32 }bits_width; inline int32_t write_data_spi1_enhanced_buffer_x_bits( void* data_address, uint32_t size, bits_width data_type ) { void* current_ptr = data_address; uint32_t step = 0; // 配置SPI模式并记录数据步长 switch( data_type ) { case bits_8: spi1_change_mode_8_bits(); step = sizeof(uint8_t); break; case bits_16: spi1_change_mode_16_bits(); step = sizeof(uint16_t); break; case bits_32: spi1_change_mode_32_bits(); step = sizeof(uint32_t); break; default: return -1; } for( uint32_t i = 0 ; i < size ; i++ ) { while( SPI1STATbits.SPITBF ); // 根据数据类型解引用并写入SPI缓冲区 switch(data_type) { case bits_8: SPI1BUF = *(uint8_t*)current_ptr; break; case bits_16: SPI1BUF = *(uint16_t*)current_ptr; break; case bits_32: SPI1BUF = *(uint32_t*)current_ptr; break; } // 按步长移动指针(转成uint8_t*确保字节级偏移) current_ptr = (uint8_t*)current_ptr + step; } return 0; }
更优的解决方案:用函数指针消除重复代码
上述修复方案仍存在for循环内的switch,可以用函数指针封装不同类型的写入逻辑,让代码更简洁、易维护,同时保留高效性:
typedef enum { bits_8, bits_16, bits_32 }bits_width; // 定义写入函数的统一接口 typedef void (*SpiWriteHandler)(void* data, volatile uint32_t* spi_buf); // 8位数据写入实现 static void spi_write_8bit(void* data, volatile uint32_t* spi_buf) { *spi_buf = *(uint8_t*)data; } // 16位数据写入实现 static void spi_write_16bit(void* data, volatile uint32_t* spi_buf) { *spi_buf = *(uint16_t*)data; } // 32位数据写入实现 static void spi_write_32bit(void* data, volatile uint32_t* spi_buf) { *spi_buf = *(uint32_t*)data; } inline int32_t write_data_spi1_enhanced_buffer_x_bits( void* data_address, uint32_t size, bits_width data_type ) { SpiWriteHandler write_handler = NULL; uint32_t step = 0; // 配置SPI模式,绑定对应写入函数和步长 switch( data_type ) { case bits_8: spi1_change_mode_8_bits(); write_handler = spi_write_8bit; step = sizeof(uint8_t); break; case bits_16: spi1_change_mode_16_bits(); write_handler = spi_write_16bit; step = sizeof(uint16_t); break; case bits_32: spi1_change_mode_32_bits(); write_handler = spi_write_32bit; step = sizeof(uint32_t); break; default: return -1; } uint8_t* current_ptr = (uint8_t*)data_address; for( uint32_t i = 0 ; i < size ; i++ ) { while( SPI1STATbits.SPITBF ); // 调用对应类型的写入函数 write_handler(current_ptr, &SPI1BUF); // 移动指针 current_ptr += step; } return 0; }
额外说明:其他代码的问题
- 代码2虽然能编译,但存在致命逻辑错误:
data_address是uint8_t*类型,*(data_address + i*x)仅会读取单个字节,对于16/32位数据,只会写入低8位,完全不符合需求,硬件测试必然失败。 - 代码3功能正常,但重复编写三次
for循环,维护性差,一旦需要修改写入逻辑(比如增加超时判断),要修改三处代码,容易出错。
内容的提问来源于stack exchange,提问作者baldhead
相关产品推荐
相关产品推荐

