C garantiert, dass uintptr_t ein Integertyp ist, also kann man damit rechnen.
Okay, aber welche Arten von Rechenoperationen sind denn damit sinnvoll?
Wiederholt durch 16 teilen und jeweils den Rest auf den Bildschirm ausgeben?
Und es erlaubt, zwei Pointer voneinander abzuziehen, wenn sie ins selbe Objekt zeigen.
Ist denn auch definiert was passieren soll wenn die zwei Pointer nicht ins selbe Objekt zeigen?
Nicht, dass ich wüsste (ich habe aber auch keine explizite Aussage gefunden, dass es undefiniert ist, der Standard scheint einfach nichts dazu zu sagen). Wenn du daraus also einen Segfault machen willst, ist das vermutlich erlaubt.
Da ich mir es als recht schwierig vorstelle zur Laufzeit die entsprechenden Bedingungen zu prüfen und eine Verletzung auch korrekt zu behandeln bin ich daher dafür solche Operationen lieber gleich ganz zu verbieten. Ich denke auch nicht dass das eine nennenswerte Einschränkung darstellt, um z.B. die Offsets von Struktur-Membern zu ermitteln gibt es doch sicher auch andere Wege.
Was ist daran schwierig? Unterschiedliche Segmente -> Segfault. Gleiche Segmente -> Differenz der Offsets wird berechnet.
Abgesehen davon, dass ich keine andere Methode kenne, die Offsets zu berechnen (wobei ich mir nichtmal sicher bin, dass die normale definiert ist - an NULL liegt schließlich kein so ein Objekt), bedeutet jede Einschränkung, dass du das Ergebnis nicht mehr C nennen kann. Du musst dich also entscheiden, ob du C willst oder nicht. "Fast C" heißt "nicht C", das ist eine neue Sprache, für die du erstmal eine ordentliche Spec schreiben solltest.
Wimre sichert der C-Standard bei Pointer-Arithmetik gar nichts zu, das läuft alles unter "implementierungsspezifisch".
Pointerarithmetik ist genau definiert, solange du innerhalb von einem Objekt (oder einem Element nach Arrayende) bleibst.
Ist dann auch definiert ob an dieser neuen Adresse auch tatsächlich Speicher vorhanden ist? Wimre nein.
Wie groß dein Array war, musst du natürlich immer noch selber wissen.
Aber wenn du ein char a[42] hast und p = &a[12], q = &a[14], dann ist genau definiert, dass p + 2 * (q - p) = &a[16] ist, zum Beispiel.
Solange man direkt bei Pointern bleibt hat der Compiler ja zumindest eine theoretische Chance das Gesamtconstruct zu verstehen und etwas sinnvolles daraus zu bauen. Das Problem an FAR-Pointern in simplen Integern ist eben das Selector-Arithmetik eigentlich keinen Sinn ergibt.
Ob der Typ ein Pointer oder ein Integer ist, spielt eigentlich nicht wirklich eine Rolle. Die interessante Beschränkung ist, dass man innerhalb eines Objekts bleiben muss. Zu char* konvertieren kannst du nämlich und darauf dann fröhlich rumrechnen und hinterher wieder in einen anderen Pointer zurückcasten. In der Praxis ist das genau dasselbe wie mit einem Integer herumzurechnen. Der theoretische Unterschied ist, dass es mit char* definiert und mit uintptr_t implementation defined.