writing
1=0;
tells the compiler to change the meaning of the number 1 to be zero, well, no compiler can really do that
.
Instead you have to take the address, cast it to a pointer and dereference it.
E.g.
*(volatile unsigned char*)1= 0;
As this looks a bit ugly, I would hide it behind a macro:
#define WRITE_BYTE_TO_ADDRESS(addr, value) (*(volatile unsigned char*)(addr)= (value))
WRITE_BYTE_TO_ADDRESS(1,0);
Or use a pointer to the byte:
const volatile unsigned char* ptr_to_one= (const volatile unsigned char*)1;
*ptr_to_one= 0;
BTW: If you expect some side effects from such accesses, use volatile as I did. Just to get it written, volatile is not mandatory.
Reading is the same, just take the part from the left size of the = and place it on the right.
unsigned char t;
t= *(volatile unsigned char*)1;