Eine x86-CPU unterscheidet historisch zwei Arten von Adressen, weil es zwei Adressräume gibt: Speicher und I/O. Die Unterscheidung wird durch den Befehl getroffen, mit dem der Zugriff stattfindet; der Adresse selbst sieht man das nicht an. Eine Adresse ist nur eine Zahl und ein Zeiger speichert auch nur diese Zahl.
Wenn du von "0x0B" liest, dann schreibt die CPU diese Zahl auf den Adressbus und sagt an, dass sie jetzt lesen möchte. Das ist eine Anweisung für alle anderen Geräte, von denen jetzt das eine Gerät, was sich bei "0x0B" angesprochen fühlt, die Daten auf den Datenbus legen soll. Bei den meisten (Speicher-)Adressen ist da entweder nichts (Lesen: Müll, Schreiben: passiert nichts) oder Speicher (Lesezugriffe lesen das, was Schreibzugriffe vorher da hingeschrieben haben). (Anmerkung: Grundsätzlich ist das immernoch so, aber die Details sind anders.)
Allerdings kann hinter einer Adresse auch eine Hardware stehen. Dafür ist der I/O-Adressraum da, geht aber auch im Speicheradressraum (MMIO). Dann liest man nicht das, was man da vorher reingeschrieben hat, sondern das, was die Hardware z.B. gerade denkt. Und man schreibt nicht, was man später wieder lesen will, sondern man weist das Gerät z.B. an, etwas zu tun. (Anmerkung: Deswegen sollte man nicht auf wahllose Adressen schreiben. Manche Hardware geht kaputt, wenn man sie falsch anspricht.)
Bits beschriften kann man in C z.B. mit Bitfeldern, oder man benutzt Bitmasken zusammen mit Bitoperationen:
0x80 ist dasselbe wie 1000 0000b, ~0x80 ist das Inverse davon (also dasselbe wie 0x7F oder 0111 1111b). Wenn du 0x80 ODER "irgendwas" machst, dann kommt als Ergebnis "irgendwas" raus, wo zusätzlich das Bit 7 gesetzt ist. Wenn du ~0x80 UND "irgendwas" machst, dann kommt als Ergebnis "irgendwas" raus, wo aber das Bit 7 gelöscht ist.
Direkt Bits adressieren kannst du auf einer x86-CPU nicht. Es gibt aber Mikrocontroller, wo das geht.