Zephyr - C - 结构的深层复制产生意外结果

问题描述 投票:0回答:1

一些背景

我目前正在使用 Zephyr 在嵌入式系统上使用低功耗蓝牙。

在服务/特性/CCCD发现过程中(我的嵌入式设备是BLE中心),我想存储每个特性,以便以后使用它们(主要是读取它们)。

为此,我使用 Zephyr 提供的链表,并使用

k_calloc()
分配我的节点。

typedef struct lst_chrc_node_s {
  sys_snode_t     node;
  struct bt_uuid  *uuid;
  uint16_t        value_handle;
  uint8_t         properties;
  uint8_t         type;
} lst_chrc_node_t;

lst_chrc_node_t *list_create_node(struct bt_gatt_chrc *chrc, uint8_t type)
{
  lst_chrc_node_t *new_node = k_calloc(1, sizeof(new_node));
  if (!new_node)
    return NULL;
  
  new_node->uuid = k_calloc(1, sizeof(new_node->uuid));
  if (!new_node->uuid)
  {
    k_free(new_node);
    return NULL;
  }
  
  print_uuid128("UUID that will be store", chrc->uuid);
  *new_node->uuid = *chrc->uuid;
  new_node->value_handle = chrc->value_handle;
  new_node->properties = chrc->properties;
  new_node->type = type;
  print_uuid128("UUID that was stored   ", new_node->uuid);

  return new_node;
}

如您所见,我想存储在函数参数中传递的 struct

bt_gatt_chrc *chrc
。但是,该结构包含一个指向另一个名为 bt_uuid
struct
的常量指针。这个 bt_uuid 结构很重要,因为我需要它从 BLE 外设读取正确的特征。

我的链表的节点没有直接的

bt_gatt_chrc
结构,但具有一一相同的成员。这是因为我无法直接将 bt_gatt_chrc 从参数复制到链表的节点,因为指向
bt_uuid
的常量指针在发现服务、特征和 CCCD 时具有相同的地址(当发现不同的 GATT 属性类型时它会发生变化,但仍然相同)对于此类属性)。

问题

创建节点并复制其中的数据后,bt_uuid 值与我从 BLE 外设收到的值不同。

这是一个标准 UUID 的日志:

[00:00:04.293,914] <inf> main: UUID received           UUID 128: 070002a4-5720-0045-2020-0013072a0000
[00:00:04.293,945] <inf> main: UUID that will be store UUID 128: 070002a4-5720-0045-2020-0013072a0000
[00:00:04.293,975] <inf> main: UUID that was stored    UUID 128: 00000d00-0d61-8c00-0200-020003000000

我觉得很愚蠢,因为AFAIU,我的问题似乎显然在这一行

*new_node->uuid = *chrc->uuid;
,但我不明白我做错了什么。我尝试将
const struct bt_uuid
转换为
struct bt_uuid
,结果也不好(看起来更错误,因为整个 128 位 UUID 在每个标准特性(由蓝牙 SIG 定义)之间发生变化,而不是停留在非常接近相同(比如特性之间只有 2-3 位数字发生变化,而无需转换结构)。

是否因为

bt_uuid
是“暂定”类型,所以我不能这样使用它?有人可以重新表述一下什么是暂定类型吗?我显然不确定我对此的理解。

c struct memory-management zephyr-rtos
1个回答
1
投票

来自uuid.h

enum {
        BT_UUID_TYPE_16,
        BT_UUID_TYPE_32,
        BT_UUID_TYPE_128,
};
 
#define BT_UUID_SIZE_16                  2
 
#define BT_UUID_SIZE_32                  4
 
#define BT_UUID_SIZE_128                 16
 
struct bt_uuid {
        uint8_t type;
};
 
struct bt_uuid_16 {
        struct bt_uuid uuid;
        uint16_t val;
};
 
struct bt_uuid_32 {
        struct bt_uuid uuid;
        uint32_t val;
};
 
struct bt_uuid_128 {
        struct bt_uuid uuid;
        uint8_t val[BT_UUID_SIZE_128];
};

struct bt_uuid *
应指向足够的内存来存储
struct bt_uuid_16
struct bt_uuid_32
struct bt_uuid_128
,具体取决于
type
成员
BT_UUID_TYPE_16
BT_UUID_TYPE_32
BT_UUID_TYPE_128
的值.

编辑:OP原始代码中的

new_node = k_calloc(1, sizeof(new_node));
行是错误的(由下面的comment中的@chux和问题的comment中的@ach发现),并且已被在下面的代码中更正了。

未经测试、修改过的代码:

lst_chrc_node_t *list_create_node(struct bt_gatt_chrc *chrc, uint8_t type)
{
  lst_chrc_node_t *new_node;
  size_t bt_uuid_size;

  switch (chrc->uuid->type)
  {
  case BT_UUID_TYPE_16:
    bt_uuid_size = sizeof(struct bt_uuid_16);
    break;
  case BT_UUID_TYPE_32:
    bt_uuid_size = sizeof(struct bt_uuid_32);
    break;
  case BT_UUID_TYPE_128:
    bt_uuid_size = sizeof(struct bt_uuid_128);
    break;
  default:
    return NULL;
  }
  new_node = k_calloc(1, sizeof(*new_node));
  if (!new_node)
    return NULL;
  
  new_node->uuid = k_calloc(1, bt_uuid_size);
  if (!new_node->uuid)
  {
    k_free(new_node);
    return NULL;
  }
  
  print_uuid128("UUID that will be store", chrc->uuid);
  memcpy(new_node->uuid, chrc->uuid, bt_uuid_size);
  new_node->value_handle = chrc->value_handle;
  new_node->properties = chrc->properties;
  new_node->type = type;
  print_uuid128("UUID that was stored   ", new_node->uuid);

  return new_node;
}
© www.soinside.com 2019 - 2024. All rights reserved.