Basic Subnet Mask Calculator + A Little Extra
Here are some things that may help you improve your program.

Prefer const to #define

For constants such as TOTAL_BITS, it's generally better to use a named const value rather than a #define.  The primary reason is that the const definition enforces type checking, while the macro does not.  However, see the next suggestion.

Use sizeof for portability

The code currently contains these lines:

#define TOTAL_BITS 32
#define N_OCTETS ((TOTAL_BITS / 8))

typedef uint32_t BitField;


However, I think I'd define everything instead as const values all derived from the type.  That is, I'd suggest this:

typedef uint32_t BitField;
const int BitFieldOctets = sizeof(BitField);
const int BitFieldBits = 8 * BitFieldOctets;


Think carefully about signed vs. unsigned

If generateSubnetMask is passed a negative number, what should it do?  I'd suggest that the passed number should be unsigned instead of int and that the value could be checked to make sure it does not exceed the naximum number of bits.  

Be careful when shifting negative values

By default, constants are int, so this code:

return ~0 &lt;&lt; nHostBits;


Should probably instead be written like this:

return ~0u &lt;&lt; nHostBits;


Avoid pointless recalculations

The code has this function:

void printOctets(BitField maskAddress) {
    for (int octetN = BitFieldOctets - 1; octetN &gt;= 0; octetN--) {
        BitField mask = generateOctetMask(octetN);
        printf("%d", (maskAddress &amp; mask) &gt;&gt; (octetN * 8));

        if (octetN &gt; 0) {
            printf(".");
        }
    }
}


This is more complex than it needs to be.  First, the mask can be generated just once for the high byte and then shifted, eliminating a number of calculations that don't need to be done:

void printOctets(BitField maskAddress) {
    BitField mask = generateOctetMask(BitFieldOctets - 1);
    for (unsigned i=BitFieldOctets; i; --i) {
        printf("%d", (maskAddress &amp; mask) &gt;&gt; (BitFieldBits - 8));
        maskAddress &lt;&lt;= 8;
        if (i != 1) {
            printf(".");
        }
    }
}


This works by keeping the mask in place over the most significant byte and then shifting the address to the left each iteration.  An alternative would be to use a union as the BitField type to allow access to each byte very simply.  That approach, however, requires that you account for the endian-ness of your machine, which this code does not.

Consider restructuring for simplicity and clarity

The printBinary code is currently like this:

void printBinary(BitField n) {
    bool areDropping = true;  // So we can drop leading 0s.

    for (BitField mask = 1u &lt;&lt; 31; mask &gt; 0; mask &gt;&gt;= 1) {
        bool isSet = n &amp; mask;

        if (isSet) {
            areDropping = false;
            printf("1");

        } else if (!areDropping) {
            printf("0");
        }
    }
}


Instead, I'd break this into two different loops: the first to skip leading zeroes and the second to actually print the bits.  Here's one way to do that:

void printBinary(BitField n) {
    BitField mask = 1u &lt;&lt; (BitFieldBits - 1);
    // skip leading zeroes
    for (; mask &amp;&amp; !(mask &amp; n); mask &gt;&gt;= 1);
    // print all other bits
    for (; mask; mask &gt;&gt;= 1) {
        putchar(n &amp; mask ? '1' : '0');
    }
}


Note that here I'm using the named constants rather than the "magic number" 31.