As mentioned by @fanl, const does indeed change the default linkage of globals in C++, and does prevent defining a variable without initialization.
But there are better ways to get external linkage than removing const. The usage of reserved arrays in the header file Chris linked is also very fragile. I would say this code leaves a lot of room for improvement -- don't emulate it.
And furthermore these variables don't get defined (that would cause the compiler and linker to select an address), they are always accessed via pointers, with the address fixed according to the memory map.
For headers intended purely for use by C++, this is how I do it (memory map matching a TI Stellaris chip).
Looks complicated, but the optimizing compiler reduces it down to a single instruction per access. And the address offsets are coded in, not dependent on the order and padding of fields inside a structure, so it's much less fragile and easier to verify against the datasheet.
template<uintptr_t extent>
struct memory_mapped_peripheral
{
char data[extent];
volatile uint32_t* offset( uintptr_t off ) { return reinterpret_cast<volatile uint32_t*>(data+off); }
volatile const uint32_t* offset( uintptr_t off ) const { return reinterpret_cast<volatile const uint32_t*>(data+off); }
};
struct LM3S_SYSTICK : private memory_mapped_peripheral<0x1000>
{
volatile uint32_t& CTRL (void) { return offset(0x010)[0]; }
volatile uint32_t& RELOAD (void) { return offset(0x014)[0]; }
volatile uint32_t& CURRENT(void) { return offset(0x018)[0]; }
}* const SYSTICK = reinterpret_cast<LM3S_SYSTICK*>(0xE000E000);
struct LM3S_NVIC : private memory_mapped_peripheral<0x1000>
{
volatile uint32_t& EN (uintptr_t i) { return offset(0x100)[i]; }
volatile uint32_t& DIS (uintptr_t i) { return offset(0x180)[i]; }
volatile uint32_t& PEND (uintptr_t i) { return offset(0x200)[i]; }
volatile uint32_t& UNPEND(uintptr_t i) { return offset(0x280)[i]; }
volatile const uint32_t& ACTIVE(uintptr_t i) const { return offset(0x300)[i]; }
volatile uint32_t& PRI (uintptr_t i) { return offset(0x400)[i]; }
volatile uint32_t& SWTRIG(void) { return offset(0xF00)[0]; }
}* const NVIC = reinterpret_cast<LM3S_NVIC*>(0xE000E000);