Gibt es noch andere Lösungen um den Inhalt ohne Zwischenspeichern
zu tauschen?
#include<stdio.h>
int main()
{
int x=10; int y=25;
x ^= y; y ^= x; x ^= y;
printf("\n x = %i y = %i ", x, y);
}
Walter K. schrieb:> Gibt es noch andere Lösungen um den Inhalt ohne Zwischenspeichern> zu tauschen?>>> #include<stdio.h>>> int main()> {> int x=10; int y=25;>> x ^= y; y ^= x; x ^= y;>> printf("\n x = %i y = %i ", x, y);> }
If you enable overflows exceptions, then pass unsigned values so an exception isn't thrown.
Wenn man diese Variante für signed integer benutzt möchte, sollte man
vorher nach unsigned casten, damit man kein undefined sondern
implementation defined behavior hat. Oder besser gleich die xor Variante
nehmen die für signed und unsigned geeignet ist.
1
Don't use this with floating-point numbers (unless you operate on their raw integer representations).
Was ist die raw integer representation eines floats?
mh schrieb:> Was ist die raw integer representation eines floats?
Das, was du bekommst, wenn du per Union eine Gleitkommazahl als Integer
interpretierst.
Warum?
Offensichtich geht es um C (steht in der Überschrift, und du machst dir
um undefined behaviour Sorgen).
Du weißt also eh nicht, was nach dem Optimieren raus kommt.
Warum nimmst du nicht die am einfachsten zu verstehende Lösung, bei der
du noch hoffen kannst dass auch der Compiler versteht was du willst,
weil er das Muster erkennt (mit Zwischenspeichern) und läßt den Compiler
optimieren?
Jemand schrieb:> mh schrieb:>> Was ist die raw integer representation eines floats?>> Das, was du bekommst, wenn du per Union eine Gleitkommazahl als Integer> interpretierst.
Soweit ich das sehe ist das legal, wenn man einen unsigned int
passender Größe nimmt. Interessant.
Sebastian schrieb:> Warum nimmst du nicht die am einfachsten zu verstehende Lösung, bei der> du noch hoffen kannst dass auch der Compiler versteht was du willst,> weil er das Muster erkennt (mit Zwischenspeichern) und läßt den Compiler> optimieren?
Ich weiß nicht, was der Anlass für diese Frage ist, aber es gibt Fälle
in denen diese Art der Optimierung notwendig ist, um Register
einzusparen.
mh schrieb:> aber es gibt Fälle> in denen diese Art der Optimierung notwendig ist, um Register> einzusparen.
Ich denke mal, das braucht mehr Register (4?) als das simple Swap (3)
(angenommen der Item passt in ein Register).
Warum das herumgeistert ist wohl nur wegen unbekannt und erstaunlich
Effekten.
leo
mh schrieb:> Jemand schrieb:>> mh schrieb:>>> Was ist die raw integer representation eines floats?>>>> Das, was du bekommst, wenn du per Union eine Gleitkommazahl als Integer>> interpretierst.> Soweit ich das sehe ist das legal, wenn man einen unsigned int> passender Größe nimmt. Interessant.
Nein, man darf immer nur auf das Union-Element zugreifen, das "aktiv"
ist, und das ist das zuletzt geschriebene.
leo schrieb:> Ich denke mal, das braucht mehr Register (4?) als das simple Swap (3)
Wofür sollten so viele Register nötig sein?
Rolf M. schrieb:>> Ich denke mal, das braucht mehr Register (4?) als das simple Swap (3)>> Wofür sollten so viele Register nötig sein?
Ja, sorry - da hab ich wohl geirrt.
leo
Rolf M. schrieb:> Nein, man darf immer nur auf das Union-Element zugreifen, das "aktiv"> ist, und das ist das zuletzt geschriebene.
C11 erlaubt das.
6.5.2.3 Structure and union members:
1
95) If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called "type punning"). This might be a trap representation.
Rolf M. schrieb:> Nein, man darf immer nur auf das Union-Element zugreifen, das "aktiv"> ist, und das ist das zuletzt geschriebene.
In C erlaubt in C++ verboten (mit Ausnahmem)
tja, dann wollt ihr Strings in irgendwelchen Schleifen durchlaufen.
Also kommt eine Laufvariable zum Einsatz. Man hat also doch eine
zusätzliche Variable.
Ich habe gerade etwas Interessantes festgestellt:
Der GCC erzeugt bei eingeschalteter Optimierung für alle drei Varianten
des folgenden Codes
1
#include<stdint.h>
2
3
#define METH 1
4
5
voidsub2(uint8_ta,uint8_tb);
6
7
voidsub1(uint8_tn,uint8_ta,uint8_tb){
8
for(uint8_ti=0;i<n;i++){
9
sub2(a,b);
10
11
#if METH==0
12
uint8_ttmp=a;
13
a=b;
14
b=tmp;
15
#elif METH==1
16
a^=b;
17
b^=a;
18
a^=b;
19
#elif METH==2
20
a-=b;
21
b+=a;
22
a=b-a;
23
#endif
24
25
}
26
}
exakt den gleichen Assemblercode. Betrachtet man diesen näher, findet
man darin die folgende Codesequenz (in Pseudoassembler, gilt sowohl für
PC als auch für AVR):
1
move reg1 to reg3
2
move reg2 to reg1
3
move reg3 to reg2
Somit braucht man sich wenigstens nicht den Kopf darüber zu zerbrechen,
welche der drei Methoden die effizienteste (in Bezug auf Laufzeit oder
Speicher) ist :)
Yalu X. schrieb:> Somit braucht man sich wenigstens nicht den Kopf darüber zu zerbrechen,> welche der drei Methoden die effizienteste (in Bezug auf Laufzeit oder> Speicher) ist :)
Was dann auch zur (wenig erstaunlichen) allumfassend Antwort auf die
Eingangsfrage führt:
Gar nicht.
Oliver
zitter_ned_aso schrieb:> ja, stimmt. man kann alles per Hand machen
Du hast es immer noch nicht verstanden: Warum soll man die Strings
iterieren, um zwei Zeiger auszustauschen?
Walter K. schrieb:> Gibt es noch andere Lösungen um den Inhalt ohne Zwischenspeichern> zu tauschen?>> #include<stdio.h>>> int main()> {> int x=10; int y=25;>> x ^= y; y ^= x; x ^= y;>> printf("\n x = %i y = %i ", x, y);> }
Bester Tipp: Lass den Quatsch, das ist nicht effizienter. Zweitbester
Tipp: Was passiert denn wenn x und y identisch sind (im Sinne identische
Variable wenn du das Konstrukt später als Makro oder inline Funktion
verpackt hast)?
Mit int in C wird das so nix. Allenfalls wenn man die Nibbles eines
Bytes vertauschen möchte könnte man beispiesweise auf ATMegas inline
Assembler verwenden um SWAP
(https://www.microchip.com/webdoc/avrassembler/avrassembler.wb_SWAP.html)
zu verwenden. Aber das ist dann nicht mehr wirklich C.
Walter K. schrieb:> x^y schrieb:>> Was passiert denn wenn x und y identisch sind>> naja .. einfach if(x^y) { /*tausche*/ }
Dann ist es aber definitiv ineffizienter als die Methode mit der
temporären Variable.
Jobst Q. schrieb:> (unsigned long)str1 ^= (unsigned long)str2;> (unsigned long)str2 ^= (unsigned long)str1;> (unsigned long)str1 ^= (unsigned long)str2;
Und was wenn "long" nicht groß genug für einen Pointer ist? Wenn schon
dann "uintptr_t" ...
Alternativ C++ verwenden und std::swap(x,y); aufrufen. Das nutzt
automatisch den optimalen Weg für den jeweiligen Typ (insb. für
Strings).
x^y schrieb:> Walter K. schrieb:>> Gibt es noch andere Lösungen um den Inhalt ohne Zwischenspeichern>> zu tauschen?>>>> #include<stdio.h>>>>> int main()>> {>> int x=10; int y=25;>>>> x ^= y; y ^= x; x ^= y;>>>> printf("\n x = %i y = %i ", x, y);>> }>> Bester Tipp: Lass den Quatsch, das ist nicht effizienter. Zweitbester> Tipp: Was passiert denn wenn x und y identisch sind (im Sinne identische> Variable wenn du das Konstrukt später als Makro oder inline Funktion> verpackt hast)?> x = y = 42;> -> x ^= y;> -> x = x ^ y;> -> x = x ^ x;> -> x = 0
Leider seh ich nicht was Du genau meinst. Vielleicht liegt es auch an
der Optimierung des GCC, allerdings glaube ich das (noch) nicht.
#include<stdio.h>
[K]ein Sohn [des] Admins (frei nach Lk 3,33) schrieb im Beitrag
#5797110:
> Leider seh ich nicht was Du genau meinst
Sollte man auf die Idee kommen das Tauschen (hässlich) in ein Makro zu
packen:
1
#define UINT_SWAP(x,y) do { (x) ^= (y); (y) ^= (x); (x) ^= (y); } while (0)
und das Makro auf einer Variable mit sich selbst aufrufen (was in
verschachtelten Konstruktionen schon mal passieren kann):
1
intmain(){
2
unsignedinta=42;
3
UINT_SWAP(a,a);
4
printf("%d\n",a);
5
}
kommt 0 heraus. Mit std::swap ist das kein Problem:
Niklas G. schrieb:> [K]ein Sohn [des] Admins (frei nach Lk 3,33) schrieb im Beitrag> #5797110:>> Leider seh ich nicht was Du genau meinst>> Sollte man auf die Idee kommen das Tauschen (hässlich) in ein Makro zu> packen:> #define UINT_SWAP(x,y) do { (x) ^= (y); (y) ^= (x); (x) ^= (y); } while> (0)
Danke, jetz seh ichs auch.
Walter K. schrieb:> Gibt es noch andere Lösungen um den Inhalt ohne Zwischenspeichern> zu tauschen?
In C kümmert sich der Compiler um die Optimierung und da sollte man ihm
gefälligst nicht ins Handwerk pfuschen.
In C gilt: Schreib es so hin, wie es am besten lesbar ist.
Irgendwelche dirty Assemblerhacks haben in C-Programmen nichts verloren.