在container_of()中使用“((type *)0) - > member”的替代方法

时间:2015-03-27 15:57:16

标签: c compiler-errors

我在代码中使用宏container_of()

然而,它的定义在算术中使用了NULL指针((type *)0),这会带来错误

pointer of type 'void *' used in arithmetic

使用不((type *)0)->member的{​​{1}}或container_of()是否还有其他选择。

代码中引发错误的行是:

NULL

真正的代码非常大。我将放置具有以上行的函数的片段:

struct net_if_rx *rx = container_of(fq, struct net_if_rx, fq);

我对container_of定义有这个:

static enum qman_cb_dqrr_result cb_rx(struct qman_portal *qm __always_unused,
                      struct qman_fq *fq,
                      const struct qm_dqrr_entry *dqrr)
{
    struct ether_header *prot_eth;
    const struct qm_fd *fd = &dqrr->fd;
    struct net_if_rx *rx = container_of(fq, struct net_if_rx, fq);

    BUG_ON(fd->format != qm_fd_contig);
    prot_eth = __dma_mem_ptov(qm_fd_addr(fd));
    prot_eth = prot_eth + fd->offset;
    /* Broadcasts and non-IP packets are not reflected. */
    if (likely(!(prot_eth->ether_dhost[0] & 0x01) &&
            (prot_eth->ether_type == ETHERTYPE_IP))) {
        struct iphdr *iphdr = (typeof(iphdr))(prot_eth + 1);
        __be32 tmp;
        /* switch ipv4 src/dst addresses */
        tmp = iphdr->daddr;
        iphdr->daddr = iphdr->saddr;
        iphdr->saddr = tmp;
        /* switch ethernet src/dest MAC addresses */
        ether_header_swap(prot_eth);
        /* transmit */
        send_frame(rx->tx_fqid, fd);
    } else
        /* drop */
        drop_frame(fd);
    return qman_cb_dqrr_consume;
}

1 个答案:

答案 0 :(得分:1)

container_of的预期实施是:

#define container_of(ptr, type, member) ({               \
    const typeof( ((type *)0)->member ) *__mptr = (ptr); \
    (type *)( (char *)__mptr - offsetof(type,member) );  \
})

请注意,我们在此代码中使用了多个gcc扩展名:Statement expressions以及null取消引用。

如果我们想编写严格符合规范的代码,我们可以删除第一个语句,它只用于为程序员提供类型安全性:

#define container_of(ptr, type, member) \
    ((type *)( (char *)(ptr) - offsetof(type, member) ))

这可以让你安静地发出警告。