【问题标题】:What is the significance of union in this code, what is the disadvantage if structure?这段代码中联合的意义是什么,如果结构有什么缺点?
【发布时间】:2015-04-30 19:38:46
【问题描述】:
struct queue_entry_s {

    odp_buffer_hdr_t *head;
    odp_buffer_hdr_t *tail;
    int               status;

    enq_func_t       enqueue ODP_ALIGNED_CACHE;
    deq_func_t       dequeue;
    enq_multi_func_t enqueue_multi;
    deq_multi_func_t dequeue_multi;

    odp_queue_t       handle;
    odp_buffer_t      sched_buf;
    odp_queue_type_t  type;
    odp_queue_param_t param;
    odp_pktio_t       pktin;
    odp_pktio_t       pktout;
    char              name[ODP_QUEUE_NAME_LEN];
};

typedef union queue_entry_u {
    struct queue_entry_s s;
    uint8_t pad[ODP_CACHE_LINE_SIZE_ROUNDUP(sizeof(struct queue_entry_s))];
} queue_entry_t;

typedef struct queue_table_t {
    queue_entry_t  queue[ODP_CONFIG_QUEUES];                                                                                           
} queue_table_t;

static queue_table_t *queue_tbl;

#define ODP_CACHE_LINE_SIZE 64

#define ODP_ALIGN_ROUNDUP(x, align)\                                                                                                   
    ((align) * (((x) + align - 1) / (align)))

#define ODP_CACHE_LINE_SIZE_ROUNDUP(x)\
    ODP_ALIGN_ROUNDUP(x, ODP_CACHE_LINE_SIZE)

在上面的代码中,typedef union queue_entry_u,union的意义是什么。如果我们取struct(typedef struct queue_entry_u),有什么缺点吗?

【问题讨论】:

  • 您应该查看ODP_CACHE_LINE_SIZE_ROUNDUP 宏,和/或将宏编辑到问题中。基本上,union 将填充字节添加到结构中,以便使用的内存是某个理想值的倍数。
  • @user3386109,按照您的要求添加了宏的定义。
  • 应该有选择2个接受的答案的选项。两个答案都说明了原因。

标签: c structure unions


【解决方案1】:

unions有几种用法:

  • union 节省了一些内存。它使spad 在内存中位于同一个位置。如果您知道只需要其中一个,那么您可以使用union,这很有用。
  • 能够迭代结构中的字段也很有用。通过将字段保存在一个联合中,您将拥有一个数组和一个结构,因此如果您遍历pad,您实质上就是在遍历s 的字节。
  • unions 通常也可用于铸造。仅使用union 将您的条目序列化为字节数组的语法更漂亮一些。
  • 在这种情况下,使用union 似乎是为了填充s 的大小以适应高速缓存行。这样,如果queue_entry_s 的大小是缓存行长度s 的精确倍数,那么pad 将位于完全相同的内存中,不会浪费空间。否则pad 将占用比s 更多的内存,并且union 的大小将始终是缓存行长度的精确倍数。

话虽如此,如果您正在为内存非常低或性能要求非常严格的设备编写嵌入式代码,那么使用unions 通常是一个好主意。它们非常危险并且很容易被误用,因为它们会意外地覆盖用于表示 union 中的另一种类型的内存。

【讨论】:

    【解决方案2】:

    让我们从 K&R 第 2 版中的联合定义开始:

    联合是一个变量,可以(在不同时间)保存 不同种类 [...]。联合提供了一种操纵不同的方法 单个存储区域中的各种数据。

    问题中的联合包含两个对象:struct queue_entry_s 类型的结构和uint8_t 的数组。重要的是要注意这两个对象在内存中重叠。具体来说,结构体的起始地址与数组的起始地址相同。如果写入结构体,数组的内容会改变,如果写入数组,结构体的内容就会改变。

    然后请注意,ODP_CACHE_LINE_SIZE_ROUNDUP 宏采用大小并计算大于或等于该大小的 64 的最小倍数。

    联合体的大小由最大成员的大小决定。所以比如sizeof(struct queue_entry_s)是80,那么pad数组的sizeof就是128,union的sizeof就是128。

    这最终让我们找到了答案。 union的目的是增加结构体使用的内存,使结构体总是使用64字节内存的倍数。

    如果您将typedef union queue_entry_u 更改为typedef struct queue_entry_u,那么内存布局将被更改。 pad 数组不会在内存中重叠 spad,而是遵循内存中的 s 结构。所以如果s占用80字节,pad占用128字节,那么typedef struct queue_entry_u会定义一个占用208字节内存的对象。这会浪费内存,并且不符合 64 倍数的要求。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-28
      • 1970-01-01
      相关资源
      最近更新 更多