You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 04:45:57