首页 > 解决方案 > 将属于 struct 的数组作为 uint8_t 指针传递给函数

问题描述

我正在使用 Renesas RA2A1 使用他们的灵活软件包,尝试通过 uart 发送数据。

我通过 uart 发送整数和浮点数,所以我创建了一个浮点数和一个 4 字节 uint8_t 数组的联合,对于整数也是如此。

我将其中一些放在一个结构中,然后将它们与一个数组放在一个联合中,该数组是该结构中包含的所有数据的大小。

我无法通过将结构中的数组传递给函数来使其工作。如果我创建一个 uint8_t 数组,它会传入并且工作正常...我不确定尝试传递数组有什么问题如我一般。

它在 R_SCI_UART_WRITE 中检查大小的断言失败,因为它是 0,所以失败。

typedef union{
    float num_float;
    uint32_t num_uint32;
    int32_t num_int32;
    uint8_t num_array[4];
} comms_data_t;

typedef struct{
    comms_data_t a;
    comms_data_t b;
    comms_data_t c;
    comms_data_t d;
    comms_data_t e;
    uint8_t lr[2];
} packet_data_t;

typedef union{
    packet_data_t msg_packet_data;
    uint8_t packet_array[22];
}msg_data_t;


/* Works */
    uint8_t myData[10] = "Hi Dave!\r\n";

    uart_print_main_processor_msg(myData);

/* Doesn't work */
msg_data_t msg_data;

/* code removed that puts data into msg_data,ex below */
msg_data.msg_packet_data.a.num_float = 1.2f;

uart_print_main_processor_msg(msg_data.packet_array);

// Functions below

 /****************************************************************************************************************/
fsp_err_t uart_print_main_processor_msg(uint8_t *p_msg)
{
    fsp_err_t err   = FSP_SUCCESS;
    uint8_t msg_len = RESET_VALUE;
    uint32_t local_timeout = (DATA_LENGTH * UINT16_MAX);
    char *p_temp_ptr = (char *)p_msg;

    /* Calculate length of message received */
    msg_len = ((uint8_t)(strlen(p_temp_ptr)));

    /* Reset callback capture variable */
    g_uart_event = RESET_VALUE;

    /* Writing to terminal */
        err = R_SCI_UART_Write (&g_uartMainProcessor_ctrl, p_msg, msg_len);
        if (FSP_SUCCESS != err)
        {
            APP_ERR_PRINT ("\r\n**  R_SCI_UART_Write API Failed  **\r\n");

            return err;
        }

        /* Check for event transfer complete */
        while ((UART_EVENT_TX_COMPLETE != g_uart_event) && (--local_timeout))
        {
            /* Check if any error event occurred */
            if (UART_ERROR_EVENTS == g_uart_event)
            {
                APP_ERR_PRINT ("\r\n**  UART Error Event Received  **\r\n");
                return FSP_ERR_TRANSFER_ABORTED;
            }
        }
        if(RESET_VALUE == local_timeout)
        {
            err = FSP_ERR_TIMEOUT;
        }


    return err;

}

fsp_err_t R_SCI_UART_Write (uart_ctrl_t * const p_api_ctrl, uint8_t const * const p_src, uint32_t const bytes)
{
#if (SCI_UART_CFG_TX_ENABLE)
    sci_uart_instance_ctrl_t * p_ctrl = (sci_uart_instance_ctrl_t *) p_api_ctrl;
 #if SCI_UART_CFG_PARAM_CHECKING_ENABLE || SCI_UART_CFG_DTC_SUPPORTED
    fsp_err_t err = FSP_SUCCESS;
 #endif

 #if (SCI_UART_CFG_PARAM_CHECKING_ENABLE)
    err = r_sci_read_write_param_check(p_ctrl, p_src, bytes);
    FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
    FSP_ERROR_RETURN(0U == p_ctrl->tx_src_bytes, FSP_ERR_IN_USE);
 #endif

    /* Transmit interrupts must be disabled to start with. */
    p_ctrl->p_reg->SCR &= (uint8_t) ~(SCI_SCR_TIE_MASK | SCI_SCR_TEIE_MASK);

    /* If the fifo is not used the first write will be done from this function. Subsequent writes will be done
     * from txi_isr. */
 #if SCI_UART_CFG_FIFO_SUPPORT
    if (p_ctrl->fifo_depth > 0U)
    {
        p_ctrl->tx_src_bytes = bytes;
        p_ctrl->p_tx_src     = p_src;
    }
    else
 #endif
    {
        p_ctrl->tx_src_bytes = bytes - p_ctrl->data_bytes;
        p_ctrl->p_tx_src     = p_src + p_ctrl->data_bytes;
    }

 #if SCI_UART_CFG_DTC_SUPPORTED

    /* If a transfer instance is used for transmission, reset the transfer instance to transmit the requested
     * data. */
    if ((NULL != p_ctrl->p_cfg->p_transfer_tx) && p_ctrl->tx_src_bytes)
    {
        uint32_t data_bytes    = p_ctrl->data_bytes;
        uint32_t num_transfers = p_ctrl->tx_src_bytes >> (data_bytes - 1);
        p_ctrl->tx_src_bytes = 0U;
  #if (SCI_UART_CFG_PARAM_CHECKING_ENABLE)

        /* Check that the number of transfers is within the 16-bit limit. */
        FSP_ASSERT(num_transfers <= SCI_UART_DTC_MAX_TRANSFER);
  #endif

        err = p_ctrl->p_cfg->p_transfer_tx->p_api->reset(p_ctrl->p_cfg->p_transfer_tx->p_ctrl,
                                                         (void const *) p_ctrl->p_tx_src,
                                                         NULL,
                                                         (uint16_t) num_transfers);
        FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
    }
 #endif

 #if SCI_UART_CFG_FLOW_CONTROL_SUPPORT
    if ((((sci_uart_extended_cfg_t *) p_ctrl->p_cfg->p_extend)->uart_mode == UART_MODE_RS485_HD) &&
        (p_ctrl->flow_pin != SCI_UART_INVALID_16BIT_PARAM))
    {
        R_BSP_PinAccessEnable();
        R_BSP_PinWrite(p_ctrl->flow_pin, BSP_IO_LEVEL_HIGH);
        R_BSP_PinAccessDisable();
    }
 #endif

    /* Trigger a TXI interrupt. This triggers the transfer instance or a TXI interrupt if the transfer instance is
     * not used. */
    p_ctrl->p_reg->SCR |= SCI_SCR_TIE_MASK;
 #if SCI_UART_CFG_FIFO_SUPPORT
    if (p_ctrl->fifo_depth == 0U)
 #endif
    {
        /* On channels with no FIFO, the first byte is sent from this function to trigger the first TXI event.  This
         * method is used instead of setting TE and TIE at the same time as recommended in the hardware manual to avoid
         * the one frame delay that occurs when the TE bit is set. */
        if (2U == p_ctrl->data_bytes)
        {
            p_ctrl->p_reg->FTDRHL = *((uint16_t *) (p_src)) | (uint16_t) ~(SCI_UART_FIFO_DAT_MASK);
        }
        else
        {
            p_ctrl->p_reg->TDR = *(p_src);
        }
    }

    return FSP_SUCCESS;
#else
    FSP_PARAMETER_NOT_USED(p_api_ctrl);
    FSP_PARAMETER_NOT_USED(p_src);
    FSP_PARAMETER_NOT_USED(bytes);

    return FSP_ERR_UNSUPPORTED;
#endif
}



标签: arrayscpointersstructunion

解决方案


这个程序有几个问题。该代码的很大一部分依赖于未定义的行为。如果用于别名,联合也是 UB,即使几乎所有 C 编译器都倾向于允许它,但如果您使用联合,我仍然更喜欢将 achar[]用于用于别名的数组。正如评论中提到的,"Hi Dave!\r\n";实际上占用了 11 个字节和空字符。使用uint8_t myData[] = "Hi Dave!\r\n";const * uint8_t = "Hi Dave!\r\n";省去麻烦会更安全。

第二个问题是strlen二进制数据无法正常工作。strlen通过搜索字符串中第一次出现的空字符来工作,因此它不适用于二进制数据。如果您传递一个在其 IEEE 754 表示中具有单个零字节的浮点值,它将标记此“字符串”的结尾。

简单明了,您的函数应声明为fsp_err_t uart_write(const char * msg, size_t msg_len);并使用uart_write(data_array, sizeof data_array);. 如果您想通过 UART 传输大小可变的消息,您还必须定义特定的通信协议,即创建可以明确解析的消息。这可能意味着:1)开头的一些cookie,2)传输数据的长度,3)实际数据,4)crc——但这超出了这个问题的范围。

因此,strlen不会告诉您数据的长度,您将自己将其传递给函数,并且您根本不需要联合。如果您选择不正确地序列化数据(例如使用protobuf或其他协议),您可以简单地将指向结构的指针传递给函数,即调用上面提到的uart_write((char*)&some_struct, sizeof some_struct);,它会像传递数组一样工作。

请注意,char在这种情况下并不意味着“ascii 字符”或“字符串中的字符”。使用 的要点char*是它是唯一合法允许别名其他指针的指针。因此,您获取一个指向 struct ( &str) 的指针,将其转换为 a char*,并将其传递给一个函数,该函数随后可以读取其在内存中的表示。我知道这R_SCI_UART_Write可能是由您的 IDE 生成的,不幸的是这些块经常使用uint8_t*而不是char*,因此您可能不得不uint8_t*在某些时候强制转换为。


推荐阅读