Wandering Thoughts archives

2021-08-01

Unix APIs are where I first saw C #define used to rename struct fields

In my entry on learning that you can use C unions for grouping struct fields into namespaces, I mentioned that the traditional version of this was done with #define to create convenient short names for fields that were actually hidden deeper in a struct than they appeared. I didn't come up with this idea on my own; instead, I'm pretty sure that where I first saw this was in Unix APIs. More exactly, in the actual implementation of Unix APIs, as visible in C header files. Most often, I think this was done because of unions in the struct, which at the time had to be named.

A typical example that I can find is in the 4.2 BSD arpa/tftp.h header:

struct tftphdr {
  short th_opcode;     /* packet type */
  union {
    short tu_block;    /* block # */
    short tu_code;     /* error code */
    char  tu_stuff[1]; /* request packet stuff */
  } th_u;
  char th_data[1];     /* data or error string */
};

#define th_block  th_u.tu_block
#define th_code   th_u.tu_code
#define th_stuff  th_u.tu_stuff

Here various #defines are being used to give short names to things that are actually inside a union. Today we could do this directly with an anonymous union, but those only officially appeared in C11 after being a GNU gcc extension.

(Another example is in the 4.2 BSD wait.h, which despite its position in the tree here was also in /usr/include; see MAKEDIRS. Another generally more internal use is in inode.h.)

This approach would have serious problems with th_block or other #definedd fields if they were also used in one of your own structs for some other purpose. But in the very old days of C, struct fields had to be globally unique across your entire program, so it was common to give them a relatively unique name and you already knew you had problems if you reused a field name from what the manpage said was a struct that was part of a library API.

(I haven't looked at how the early C compilers implemented struct fields, but I suspect that the V7 C compiler just put all struct field names into a global table with their type and offset. This seems a very V7 shortcut.)

unix/UnixCDefinesForFields written at 23:09:22; Add Comment


Page tools: See As Normal.
Search:
Login: Password:
Atom Syndication: Recent Pages, Recent Comments.

This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.