在这段代码中union的意义是什么,如果结构有什么缺点?

时间:2015-04-30 19:38:47

标签: c structure unions

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 ,联合的意义是什么。如果我们采用结构( typedef struct queue_entry_u ),是否有任何缺点?

2 个答案:

答案 0 :(得分:8)

unions有几种用法:

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

据说,如果您为内存非常低或性能要求非常严格的设备编写嵌入式代码,通常只使用unions是个好主意。它们非常危险并且很容易被误写,因为它意外地写了代表union中另一种类型的内存。

答案 1 :(得分:1)

让我们从K& R第二版的联盟定义开始:

  

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

问题中的联合包含两个对象:类型为struct queue_entry_s的结构和一个uint8_t数组。重要的是要注意这两个对象在内存中重叠。具体而言,结构开始的地址与数组开始的地址相同。如果你写入结构,数组的内容将被更改,如果你写入数组,那么结构的内容将被更改。

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

联合的大小由最大成员的大小决定。例如,如果sizeof(struct queue_entry_s)为80,那么pad数组的sizeof将为128,并且union的size将为128.

这最终给我们带来了答案。联合的目的是增加结构使用的内存,以便结构总是使用64字节内存的倍数。

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