You can use some kind of pointer or other, for example:
#include <stdint.h>
uint32_t volatile * p = (uint32_t volatile *) 0x11111111;
uint64_t volatile * q = (uint64_t volatile *) 0x22222222;
++*p; // read-modify-write
(Note that this specific example is almost certainly bogus, since neither address seems to be aligned properly for the respective type.)
As you say, qualifying the pointers as volatile
is necessary if the values stored at those addresses can change from outside your program; with volatile
you tell the compiler that no assumptions may be made about the value (e.g. constant propagation or common subexpression elimination may not be done for volatile values).