簡體   English   中英

在 c 中在運行時取消引用指針

[英]Dereferencing a pointer at runtime in c

我正在嘗試根據傳遞給 function 的數據類型取消引用指針,只是為了學習。

代碼 1:第一次嘗試。 顯然它沒有用。

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 )
{       
    switch( data_type )
    {
        case bits_8:
            spi1_change_mode_8_bits();
            uint8_t* dt = (uint8_t*)data_address; 
        break;

        case bits_16:
            spi1_change_mode_16_bits();
            uint16_t* dt = (uint16_t*)data_address;   
        break;

        case bits_32:            
            spi1_change_mode_32_bits();
            uint32_t* dt = (uint32_t*)data_address;    
        break;
        
        default:
            return -1;
        break;
    }
        
    for( uint32_t i = 0 ; i < size ; i++ )
    {       
        while( SPI1STATbits.SPITBF );    
        SPI1BUF = *dt++;  // Write the data out to the SPI1 peripheral. *dt++ = dt[i].
    }
    
    return 0;
}

代碼 2:看起來不錯(編譯)。 未經硬件測試。

typedef enum
{
    bits_8,
    bits_16,
    bits_32
}bits_width;


inline int32_t write_data_spi1_enhanced_buffer_x_bits( uint8_t* data_address, uint32_t size, bits_width data_type )
{       
    uint32_t x;
    
    switch( data_type )
    {
        case bits_8:
            spi1_change_mode_8_bits();
            x = 1; 
        break;

        case bits_16:
            spi1_change_mode_16_bits();
            x = 2;   
        break;

        case bits_32:            
            //spi1_change_mode_32_bits();
            x = 4;    
        break;
        
        default:
            return -1;
        break;
    }
        
    for( uint32_t i = 0 ; i < size ; i++ )
    {       
        while( SPI1STATbits.SPITBF );    
        SPI1BUF = *( data_address + (i*x) );  // Write the data out to the SPI1 peripheral.
    }
    
    return 0;
}

代碼 3:我不想將 for 循環寫 3 次(每種數據類型一個)。

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 )
{       
    switch( data_type )
    {
        case bits_8:
            spi1_change_mode_8_bits();
            uint8_t* dt = (uint8_t*)data_address; 

            for( uint32_t i = 0 ; i < size ; i++ )
            {       
                while( SPI1STATbits.SPITBF );    
                SPI1BUF = *dt++;  // Write the data out to the SPI1 peripheral. *dt++ = dt[i].
            }

        break;

        case bits_16:
            spi1_change_mode_16_bits();
            uint16_t* dt = (uint16_t*)data_address;   

            for( uint32_t i = 0 ; i < size ; i++ )
            {       
                while( SPI1STATbits.SPITBF );    
                SPI1BUF = *dt++;  // Write the data out to the SPI1 peripheral. *dt++ = dt[i].
            }

        break;

        case bits_32:            
            spi1_change_mode_32_bits();
            uint32_t* dt = (uint32_t*)data_address;    

            for( uint32_t i = 0 ; i < size ; i++ )
            {       
                while( SPI1STATbits.SPITBF );    
                SPI1BUF = *dt++;  // Write the data out to the SPI1 peripheral. *dt++ = dt[i].
            }
        break;
        
        default:
            return -1;
        break;
    }

    return 0;        
}

如何使代碼 1 工作?

或者有更好的解決方案嗎?

謝謝。

您可以使用宏創建 3 個獨立的函數:

#define TFUNC(X)                                     \
    inline void funcdef_##X(X* dt, uint32_t size) {  \
        spi1_change_mode_##X();                      \
        for (uint32_t i = 0; i < size; i++) {        \
            while (SPI1STATbits.SPITBF)              \
                ;                                    \
            SPI1BUF = *dt++;                         \
        }                                            \
    }

TFUNC(uint8_t)
TFUNC(uint16_t)
TFUNC(uint32_t)

注意:您必須將spi1_change_mode_8_bits重命名為spi1_change_mode_uint8_t等才能使上述工作正常。

然后使用_Generic作為前端:

#define write_data_spi1_enhanced_buffer_x_bits(X,S) \
             _Generic((X),                          \
                uint8_t* : funcdef_uint8_t,         \
               uint16_t* : funcdef_uint16_t,        \
               uint32_t* : funcdef_uint32_t)        \
             (X, S)

然后,您可以通過將data_address轉換為正確的類型來調用它,它會調用 select 正確的 function。 例子:

inline int32_t rite_data_spi1_enhanced_buffer(void* data_address, uint32_t size,
                                              bits_width data_type) {
    switch (data_type) {
    case bits_8:
        write_data_spi1_enhanced_buffer_x_bits((uint8_t*)data_address, size);
        break;
    case bits_16:
        write_data_spi1_enhanced_buffer_x_bits((uint16_t*)data_address, size);
        break;
    case bits_32:
        write_data_spi1_enhanced_buffer_x_bits((uint32_t*)data_address, size);
        break;
    default:
        return 1;
    }
    return 0;
}

我不喜歡這種 C “通用”語法。

我會簡單:

  1. 避免指針雙關
  2. switch()... case設置寄存器
inline int32_t write_data_spi1_enhanced_buffer_x_bits( void* data_address, uint32_t size, bits_width data_type )
{       
    unsigned char *uda = data_address;
    uint16_t u16;
    uint32_t u32;
    
    for( uint32_t i = 0 ; i < size ; i++ )
    {       
        while( SPI1STATbits.SPITBF );
            switch( data_type )
            {
            case bits_8:
                SPI1BUF = uda[i];
                break;

            case bits_16:
                memcpy(&u16, uda + sizeof(u16) * i, sizeof(u16));
                SPI1BUF = u16;
                break;

            case bits_32:            
                memcpy(&u32, uda + sizeof(u32) * i, sizeof(u32));
                SPI1BUF = u32;
                break;
            
            default:
                return -1;
            break;
            }    
    }
}

memcpy將針對不需要特殊 alignment 的目標進行優化。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM