Here I want to cover two great uses for the CONTAINING_RECORD macro. CONTAINING_RECORD has been a part of the DDK since forever, and it has a second cousin in Standard C by the name of offsetof.
For those that don’t use it regularly, it looks about like this:
typedef struct _BUFFER {
LIST_ENTRY e;
UCHAR *buf;
} BUFFER, *PBUFFER;
...
PLIST_ENTRY entry = RemoveHeadList(&listHead);
PBUFFER a = CONTAINING_RECORD(entry, BUFFER, e);
The macro returns a pointer to a data structure given the address of an element inside that structure, as shown above. Although you can get by without it most of the time, there are a couple of good reasons to use it.
First, it helps prevent bugs by keeping you from hard-coding structure offsets elsewhere in your code. For example, take the BUFFER struct above. You could, of course, simply cast BUFFER to LIST_ENTRY, but that encodes the position of e forever in your code. If you change the position (e.g. by adding a member above e in the definition), you will break all instances of code that rely on this layout.
Using CONTAINING_RECORD, on the other hand, allows you to write offset-independent code to refer to elements within the structure. Obviously this won’t work for code that was compiled against a different version of the structure – this is a compile-time technique. But it can mask otherwise silent errors. (Well, silent until the code path in question is executed…)
The reason that they’re silent is also the second great reason to use CONTAINING_RECORD: casts. I’ve written before about how much I like casts in code, so I’m implicitly for anything that eliminates casts. Since CONTAINING_RECORD returns the right type by definition, you no longer have to cast it. So:
PBUFFER buf = (PBUFFER)RemoveHeadList(&listHead);
becomes:
PBUFFER buf = CONTAINING_RECORD(
RemoveHeadList(&listHead), BUFFER, e);
This has the added bonus of being able to tell when things change out from under it, so it won’t produce as many silent error of the type described above.