0

I am using the macro container_of() in my code.

However its definition uses a NULL Pointer ((type *)0) in arithmetic which brings up the error

pointer of type 'void *' used in arithmetic

Is there any other alternative to using ((type *)0)->member or container_of() which doesn't use NULL.

The line in the code that brings up the error is this:

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

The real code is quite big. I'll put the snippet of the function that has the above line:

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;
}

I have this for container_of definition:

#ifndef container_of
#define container_of(ptr, type, member) \
 ((type *)                              \
   (  ((char *)(ptr))                   \
    - ((char *)(&((type*)0)->member)) ))

#endif
Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
user361537
  • 21
  • 3
  • 1
    This `((type *)0)` is not a pointer of type `void` it's a pointer of type `type`. – Iharob Al Asimi Mar 27 '15 at 15:59
  • 1
    Please show us the _problematic_ code – Sourav Ghosh Mar 27 '15 at 16:01
  • I read it here that ((type *)0) basically means NULL? http://stackoverflow.com/questions/8207281/c-what-does-this-macro-mean – user361537 Mar 27 '15 at 16:02
  • 1
    It's NULL but it's a _typed_ NULL. In other words, it's a pointer to the given type with the object at address zero. You'll get a SEGV if you try to dereference it but you can do arithmetic on pointers to members. – Brian White Mar 27 '15 at 16:09
  • 1
    `((type*)0)` is a null pointer of type `type*`. No "basically" or other qualification about it -- that's explicitly set forth in the C standard. – John Bollinger Mar 27 '15 at 16:10
  • You say you're "using the macro `container_of` ", but that's not a standard thing, so noone knows what you are actually using. Show the definition of this `container_of` macro that you're talking about and there might be a chance of getting an answer to your question.... – Chris Dodd Mar 27 '15 at 16:13
  • This code is embedded in squid source code which has its way to compile files. If I use it outside squid it compiles easily with gcc. However when I build squid, this code is compiled along with it and I get this error. Thus was looking for any alternatives? – user361537 Mar 27 '15 at 16:16
  • Use __builtin_offsetof if you've got it. – Carl Norum Mar 27 '15 at 16:24
  • 1
    I'm inclined to guess that you are misdiagnosing the problem. The error message you report does not seem to correspond to the macro expression `((type *)0)->member`. However, I could imagine some implementations of such a macro producing that error, for some compilers, in the event its pointer argument had type `void *`. If that's the source of the error then either casting the argument to `char *` or modifying the macro is probably the right solution. Without seeing the actual macro definition, however, that's pretty speculative. – John Bollinger Mar 27 '15 at 16:25
  • Yeah, I guess ((type *)0)->member is actually not the cause of error. I think I'll have to change the macro definition as typecasting to char * also doesn't work. I crosschecked, no arguments are void *. – user361537 Mar 27 '15 at 16:44

1 Answers1

1

The expected implementation of container_of is:

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

Note that we are using multiple gcc extensions in this code: Statement expressions as well as the null dereference.

If we wanted to write strictly conforming code, we could remove the first statement, which only serves to provides type safety to the programmer:

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

This has the additional benefit of quieting the warning that you are getting.

Community
  • 1
  • 1
Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
  • Thanks. I used this definition but the error is still there. This code is embedded in squid source code which has its way to compile files. If I use it outside squid it compiles easily with gcc. However when I build squid, this code is compiled along with it and I get this error. Thus was looking for alternative. – user361537 Mar 27 '15 at 16:28
  • 1
    `((type *)( (char *)(1 ? (ptr) : (type *)0) - offsetof(type, member) ))` is a portable way with type-safety. – mafso Mar 27 '15 at 16:31