Forum: PC-Programmierung C++: Warum kein xor auf Pointer?


von Kaj (Gast)


Lesenswert?

Hallo Forum,

um 2 Werte zu tauschen kann man sich eine extra Variable anlegen, oder 
aber die beiden Werte per xor tauschen (spart die extra Variable).
1
int a = 5;
2
int b = 7;
3
4
a = a ^ b;
5
b = a ^ b;  //  b = 5
6
a = a ^ b;  //  a = 7

Warum genau ist die xor-Operation auf Pointer nicht zulaessig?
1
int a = 5;
2
int b = 7;
3
    
4
int *x = &a;
5
int *y = &b;
6
7
x = x ^ y;
8
y = x ^ y;  //  y = &a
9
x = x ^ y;  //  x = &b
1
invalid operands of types 'int*' and 'int*' to binary 'operator^'

C++, GCC 7.1.1


Die Sinnhaftigkeit sei mal dahingestellt. Mich interessiert nur, warum 
das nicht erlaubt ist.

Gruesse

von Lars R. (larsr)


Lesenswert?

Kaj schrieb:
> Warum genau ist die xor-Operation auf Pointer nicht zulaessig?

Weil das Unsinn ist (Speicheradressen verwürfeln.)
1
*x = *x ^ *y;

bzw.
1
*x ^= *y;

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

1
std::swap (x, y);

o Zeiger sind keine Skalare, sondern eben Zeiger.

o XOR macht Mist wenn die Adressen übereinstimmen.

> Mich interessiert nur, warum das nicht erlaubt ist.

Weil's im C(++) Standard steht.

: Bearbeitet durch User
von Guardians of the memory space (Gast)


Lesenswert?

Lars R. schrieb:
> Kaj schrieb:
>> Warum genau ist die xor-Operation auf Pointer nicht zulaessig?
>
> Weil das Unsinn ist (Speicheradressen verwürfeln.)

Nach Sinnhaftigkeit war nicht gefragt!
Wenn es in Assembler (Adressarithmetik,-berechnung) möglich sein, warum 
weigert sich der Compiler? Vorrauseilender Gehorsam im Sinne der MMU?

von Tom (Gast)


Lesenswert?

Weil es völlig idiotisch wäre, sowas zu tun.

von Decoder (Gast)


Lesenswert?

Weil die Designer das so entschieden haben. Du wirst feststellen müssen, 
dass praktisch alle binären mathematischen Operationen zwischen 2 
Pointern nicht erlaubt sind - es ist in praktisch jedem Fall ein Fehler 
des Programmierers, der dazu führt. Und wenn es unbedingt trotzdem sein 
muss, kann ein einfacher cast, quasi als "ich weis was ich da mache", 
die Einschränkung aushebeln...

von TriHexagon (Gast)


Lesenswert?

Guardians of the memory space schrieb:
> Lars R. schrieb:
>> Kaj schrieb:
>>> Warum genau ist die xor-Operation auf Pointer nicht zulaessig?
>>
>> Weil das Unsinn ist (Speicheradressen verwürfeln.)
>
> Nach Sinnhaftigkeit war nicht gefragt!
> Wenn es in Assembler (Adressarithmetik,-berechnung) möglich sein, warum
> weigert sich der Compiler? Vorrauseilender Gehorsam im Sinne der MMU?

Das hat nichts mit Verweigerung zu tun, man hat sich bei der 
Standardisierung von C überlegt welche Operatoren für Adresstypen 
benötigt werden und oh wunder xor ist nicht dabei, weil es keinen 
Anwendungsfall dafür gibt. In C (und überall sonst wo) sind Zeiger eben 
keine Skalare. In Assembler ist das möglich, weil Adressen und alles 
Skalare sind, eine CPU kennt keine Datentypen im klassischen Sinne, 
deshalb ist das in Assembler möglich.

von Ulli N. (Gast)


Lesenswert?

Kaj schrieb:
> Mich interessiert nur, warum
> das nicht erlaubt ist.

Wenn es technisch sehr einfach möglich wäre zu verhindern, dass ein 
Autofahrer sein Fahrzeug gegen einen Baum lenken kann, fändest du es 
dann sinnvoll oder nicht, dieses Feature in jedes Auto einzubauen?

von Baldrian (Gast)


Lesenswert?

So geht es:
1
    int main()
2
{
3
    int *x;
4
    int *y;
5
    int *z;
6
7
    z = (int)x ^ (int)y;
8
}

von Dr. Sommer (Gast)


Lesenswert?

Baldrian schrieb:
> So geht es:
Aber nicht auf einem x86_64, denn da sind Pointer größer als Integer. 
Wenn schon mit uintptr_t.

Guardians of the memory space schrieb:
> Wenn es in Assembler (Adressarithmetik,-berechnung) möglich sein
Pointer müssen nicht notwendigerweise Adressen beinhalten, sondern 
können auch mithilfe irgendeiner anderen Form von Referenz implementiert 
sein. Daher macht eine XOR-Operation darauf keinen Sinn. Ohnehin sind 
nur ganz bestimmte wenige Pointerarithmetiken wohldefiniert.

Zum Tauschen zweier Werte gibt es std::swap. Das funktioniert auch mit 
Pointern.

von Baldrian (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Baldrian schrieb:
>> So geht es:
> Aber nicht auf einem x86_64, denn da sind Pointer größer als Integer.

Irrelevant. Wichtig ist, dass es auf meinem System funktioniert.

von Dr. Sommer (Gast)


Lesenswert?

Baldrian schrieb:
> Irrelevant. Wichtig ist, dass es auf meinem System funktioniert.
Genau, wer kommt schon auf die Idee Software zu verkaufen sodass sie 
auch auf dem System des Kunden läuft. Oder sich einen neuen Computer 
zuzulegen.

von Dumdi D. (dumdidum)


Lesenswert?

Ich vermute das liegt auch daran, das keine 'normale' Arithmetik 
stattfindet. Der numerische Wert von ein Pointer + Zahl ist der 
numerische Wert des Pointers plus die Size des Pointertyps mal Zahl.
D.h. wenn man mit dem Bitmuster arbeiten will kann man ja immer noch 
casten.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Aus

1
#include <algorithm>
2
#include <stdint.h>
3
4
int *x, *y;
5
6
void swap1() {
7
  x = reinterpret_cast<int *>(reinterpret_cast<intptr_t>(x)
8
                            ^ reinterpret_cast<intptr_t>(y));
9
  y = reinterpret_cast<int *>(reinterpret_cast<intptr_t>(x)
10
                            ^ reinterpret_cast<intptr_t>(y));
11
  x = reinterpret_cast<int *>(reinterpret_cast<intptr_t>(x)
12
                            ^ reinterpret_cast<intptr_t>(y));
13
}
14
15
void swap2() {
16
  int *tmp = x;
17
  x = y;
18
  y = tmp;
19
}
20
21
void swap3() {
22
  std::swap(x, y);
23
}

macht der GCC auf meinem PC

1
_Z5swap1v:
2
  movq  y(%rip), %rax
3
  movq  x(%rip), %rdx
4
  movq  %rax, x(%rip)
5
  movq  %rdx, y(%rip)
6
  ret
7
8
_Z5swap2v:
9
  movq  x(%rip), %rax
10
  movq  y(%rip), %rdx
11
  movq  %rax, y(%rip)
12
  movq  %rdx, x(%rip)
13
  ret
14
15
_Z5swap3v:
16
  movq  x(%rip), %rax
17
  movq  y(%rip), %rdx
18
  movq  %rax, y(%rip)
19
  movq  %rdx, x(%rip)
20
  ret

Warum sollte man also nicht das von Johann vorgeschlagene std::swap()
verwenden?

von Baldrian (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Baldrian schrieb:
>> Irrelevant. Wichtig ist, dass es auf meinem System funktioniert.

> Genau, wer kommt schon auf die Idee Software zu verkaufen sodass sie
> auch auf dem System des Kunden läuft. Oder sich einen neuen Computer
> zuzulegen.

Danke, dass du mir zustimmst.

Nebenbei: Ich gestatte dir, unter Nennung meines Urheberrechtes und der 
Zahlung von angemessenen Tantiemen, mein Programm in deinem Sinne zu 
erweitern und zu verkaufen. Viel Glück.

Beitrag #5058440 wurde vom Autor gelöscht.
von Nein! (Gast)


Lesenswert?

Baldrian schrieb:
> So geht es:
>     int main()
> {
>     int *x;
>     int *y;
>     int *z;
>
>     z = (int)x ^ (int)y;
> }

Nein!

von Achim.S (Gast)


Lesenswert?

Operatoren sind in C irgendwie definiert.
Sie sind sogar überladen und funktionieren bei unterschiedlichen Typen 
ganz unterschiedlich, auch wenn versucht wird, das ganze in sich stimmig 
zu halten.

int *pi;
int i;

pi++ macht etwas ganz anderes als i++. genauso ist es mit i+3 und 
pi+3. Warum sollte also das mit dem XOR anders sein.

von Εrnst B. (ernst)


Lesenswert?

TriHexagon schrieb:
> Das hat nichts mit Verweigerung zu tun, man hat sich bei der
> Standardisierung von C überlegt welche Operatoren für Adresstypen
> benötigt werden und oh wunder xor ist nicht dabei, weil es keinen
> Anwendungsfall dafür gibt.

Doch, gibt einen.

Du kannst eine doppelt verkettete Liste mit nur einem Pointer pro 
Element basteln, wenn du bei jedem Element "PREV XOR NEXT" speicherst.

Durchlaufen der Liste geht in beide Richtungen, man muss nur immer den 
letzten Pointer aufheben, um den nächsten zu errechnen...

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

Εrnst B. schrieb:
> Durchlaufen der Liste geht in beide Richtungen, man muss nur immer den
> letzten Pointer aufheben, um den nächsten zu errechnen..
Na sowas. Das ginge aber auch mit "next - prev". Nur leider darf man 
keine Pointer subtrahieren die nicht in das selbe Array zeigen...

von A. S. (Gast)


Lesenswert?

Und zudem muss man dann zu einem Objekt zusätzlich einen weiteren 
Pointer übergeben oder speichern.

von Joachim B. (jar)


Lesenswert?

Ulli N. schrieb:
> Wenn es technisch sehr einfach möglich wäre zu verhindern, dass ein
> Autofahrer sein Fahrzeug gegen einen Baum lenken kann, fändest du es
> dann sinnvoll oder nicht, dieses Feature in jedes Auto einzubauen?

sinnvoller den Baum zu nehmen als am Abhang dem Baum auszuweichen.

: Bearbeitet durch User
von Nop (Gast)


Lesenswert?

Ein wesentlicher Grund, wieso Pointer im C-Standard so eingeschränkt 
sind: Das müssen technisch gesehen nicht unbedingt Integer sein. 
Besonders bei Architekturen, die über Segment und Offset arbeiten, oder 
mit Banks.

Das sind dann Implementationsfragen, von denen C gerade abstrahieren 
soll.

von Rolf M. (rmagnus)


Lesenswert?

Nop schrieb:
> Ein wesentlicher Grund, wieso Pointer im C-Standard so eingeschränkt
> sind: Das müssen technisch gesehen nicht unbedingt Integer sein.
> Besonders bei Architekturen, die über Segment und Offset arbeiten, oder
> mit Banks.

Bis hin zu Zeigern, bei denen bestimmte Werte komplett ungültig sind und 
nicht mal ohne Hardware-Exception in ein Adress-Register geladen werden 
können. Da könnte dann so ein temporäres XOR-Ergebnis schon das ganze 
Programm zum Absturz bringen.

> Das sind dann Implementationsfragen, von denen C gerade abstrahieren
> soll.

Richtig.

von Nase (Gast)


Lesenswert?

Guardians of the memory space schrieb:
> Wenn es in Assembler (Adressarithmetik,-berechnung) möglich sein, warum
> weigert sich der Compiler? Vorrauseilender Gehorsam im Sinne der MMU?
Nein (bzw. auch, je nach Architektur).
Hauptsächlich wegen Typensicherheit.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.