arrays - 将属于 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
}
解决方案
这个程序有几个问题。该代码的很大一部分依赖于未定义的行为。如果用于别名,联合也是 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*
在某些时候强制转换为。
推荐阅读
- c# - 如何知道我的控制台解决方案是否实时向我的数据库插入数据?使用日志?
- r - 如何保存由 varImpPlot 函数生成的图(随机森林)
- javascript - 单击时,如果有课程则提醒,否则添加课程问题
- ios - 如何在swift中为数组内的字典制作模型类?
- apache-flink - 下沉到Destination后的流程元素
- c++ - 使用 Visual Studio 2015 x64 和 CMake 构建 TBB
- oauth-2.0 - 保护 Rest API
- oracle - 用于同时获取结果和更新表列的 Oracle 脚本
- jquery - 当我在 BigCommerce 中使用 jquery 调用 api 以获取复杂规则时,我收到状态代码:403
- office-ui-fabric - 如何取消选择 Pivot Office UI Fabric React 中的第一个 PivotItem