I realize that the documentation says that the argument should be an integer type when using %X etc. format specifiers, so it works as I expected with
writefln("p = %08X", cast(int)p);
etc. 
But even so accepting a non-integer type and then supposing small values are only 16 bits seems a bit odd.