Tuesday, April 18, 2006

NetBSD's KNF: Prefixes for struct members

The NetBSD coding style guide, also known as Kernel Normal Form (KNF), suggests to prefix a struct's members with a string that represents the structure they belong to. For example: all struct tmpfs_node members are prefixed by tn_ and all struct wsdisplay_softc members start with sc_. But why there is such a rule? After all, the style guide does not mention the reasons behind this.

The first reason is clarity. When accessing a structure instance, whose name may be anything, seeing a known prefix in the attribute helps in determining the variable's type. For example, if I see foo->sc_flags, I know that foo is an instance of some softc structure. As happens with all clarity guidelines, this is subjective.

But there is another reason, which is not more technical. Using unprefixed names pollutes the global namespace, a specially dangerous situation if the structure belongs to a public header. Why? Because of the preprocessor — that thing that should have never existed — or more specifically, the macros provided by it.

Let's see an example: consider a foo.h file that does this:
#ifndef _FOO_H_
#define _FOO_H_

struct foo {
int locked;
};

#endif
And now take the following innocent piece of code:
#define locked 1
#include <foo.h>
Any attempt to access struct foo's locked member will fail later on because of the macro definition. Prefixing the variable mitigates this situation.

3 comments:

Anonymous said...

I think there is another reason, which goes back a long way in time. Back then, compilers couldn't keep the 'item' in

struct foo { int item };
and
struct bar { int item };

apart, they somehow clashed (don't ask me about details). Not an issue with modern compilers, but I think it's still nice to have a rough idea about what you're accessing when you do so. Which is completely different from languages like C++, where you never know what you actually access when you grab var->item.


- Hubert

Anonymous said...

In old C compilers, structure members didn't live in a namespace local to the structure. Member prefixes prevented name collisions. The habit stuck, and some people argue it is clearer.

By the way, "#define locked 1" is bad practice in C. Macro definitions should have uppercase names in order to prevent such problems, so your example doesn't really motivate member prefixes. You would have to prefix all variables and functions too in order to be safe from macros like the one you suggests.

The C preprocessor is a powerful tool, but it is also dangerous. The convention of naming macros in uppercase was invented for a reason.

Consider this example:

#define LOCKED 1 /* uppercase */

struct foo {
int locked;
};

int locked; /* this will also work */

Julio M. Merino Vidal said...

I know that the typical C convention is to use uppercase letters for macro names... but it is not unusual to find some "functions" declared as macros for speed (if e.g. debugging is disabled), thus using lowercase names.

Anyway, thanks to both of you for pointing this out: old compilers did not handle the same name in different structures properly so this was the (possibly) only workaround.