Nil Struct Pointer
A nil struct is a pre-allocated struct that resides in read-only memory and represents a nil version of the type. A pointer to this struct can be returned instead of a nullpointer in case of failure.
Pointers inside the nil struct should point to other nil structs and can be self-referential (e.g. in case of a linked-list).
Returning a nil struct pointer indicates an error, but the receiving code cannot overwrite the empty defaults of the pointer. This way, the error will propagate through the same codepaths as valid data, and can be handled later on.
Example
struct Node { Node *first, *last, *next, *prev, *parent; int v; }; // MSVC read_only #pragma section(".roglob", read) #define read_only (__declspec(allocate(".roglob")) // GCC/Clang read_only #define read_only __attribute__((section (".text#"))) read_only Node nil_node = {&nil_node, &nil_node, &nil_node, &nil_node, &nil_node};
In the conventional approach of using null pointers, code that works on this type may look like this:
Node *SearchTreeForInterestingChain(Node *root) { Node *result = 0; if(root) { Node *n1 = ChildFromValue(root, 1); if(n1) { Node *n2 = ChildFromValue(n1, 2); if(n2) { result = ChildFromValue(n2, 3); } } } return result; }
With the nil struct approach, the code shrinks in complexity:
Node *SearchTreeForInterestingChain(Node *root) { Node *n1 = ChildFromValue(root, 1); Node *n2 = ChildFromValue(n1, 2); Node *n3 = ChildFromValue(n2, 3); // we will return, and all callers can dereference this 'invalid' result return n3; }
Motivation
The conventional approach to avoid access violations is by catching invalid
pointers with the help of if
and assert
:
foo_ *foo = malloc(sizeof(foo_t)); assert(foo != 0); init_foo(foo); bar_t *bar = foo->bar; if (bar) { // use bar }
This is good for genuine failure cases, i.e. failing to allocate a buffer, but
the complexity grows with each if
, assert
and early return - doubling the
codepaths in the process.
If the pointer is only being read from and a nullpointer does not indicate an allocation error, returning a nil struct pointer can reduce complexity.