Hacker News new | ask | show | jobs
by gilgad13 5360 days ago
In C, at least, it helps to think of regions of memory independently of any meaning overlaid on top. For instance, there is plenty of code that depends on behavior like this:

    struct list_node {
        struct list_node * next;
        struct list_node * prev;
    }
    
    struct useful {
        /* This struct should be part of a list, so include the list header first */
        struct list_node;
    
        /* That data that this struct is storing follows */
        in_addr_t sip;
        in_port_t sport;
        in_addr_t dip;
        in_addr_t dport;
    
    }
Then, you can write a generic list walker by casting the a "struct useful * " to a "struct list_node * " since the first fields will match up.

This is just one example, another would be parsing and unwrapping ip headers and data sections. As I'm sure you've noticed, C prefers explicit to implicit, and this applies to the layout of memory as well.

edit: example: http://stackoverflow.com/questions/3766229/casting-one-struc...

2 comments

I believe libglib/GObject uses this pattern for implementing inheritance in C as well: https://en.wikipedia.org/wiki/GObject#Class_implementation
The first named element of a structure is required to be located at the same address as the structure, yes; but I'm not aware of any requirement beyond that.

Can you point me at the relevant paragraph?

Elements are required to be "sequentially allocated":

This is from the draft N1256 document as I don't have access to the official standard. From 6.2.5 - Types:

"A structure type describes a sequentially allocated nonempty set of member objects (and, in certain circumstances, an incomplete array), each of which has an optionally specified name and possibly distinct type"

I can say that a lot of device drivers in the Linux kernel depend on this ...

Hmm, I understood "sequentially allocated" to mean "this structure gets a block of memory and no other variables will be allocated space within that block". Your interpretation would make sense, though.

As for Linux device drivers... it wouldn't be the first time that the Linux kernel (and especially device drivers) assumed a certain compiler behaviour which wasn't guaranteed, with hilarious results on later compilers.