Frage zu swap()



  • Betrachte diesen Code:

    void swap(int a, int b)
    {
        int c = a;
        a = b;
        b = c;
    }
    
    void foo()
    {
        int x=5;
        int y=7;
        swap(x,y); /* x=5, y=7 */
    }
    

    Innerhalb von swap, (Gültigkeitsbereich von a und b) hast du den Inhalt von a und b tatsächlich getauscht, aber sobald die Funktion swap verlassen wird, gehen swap::a und swap::b ins Nirvana, foo::x und foo::y bleiben Intakt. Damit andere Funktionen den Wert von Variablen ändern können, die nicht in diesem Gültigkeitsbereich definiert sind, benutzt man Zieger. Ein Zeiger ist nur eine Varaible, die auf eine andere zeigt, sprich, der Zeiger speichert die Adresse der gezeigte Variable:

    void swap(int* a, int* b)
    {
        int c = *a;
        *a = *b;
        *b = *c;
    }
    
    void foo()
    {
        int x=5;
        int y=7;
        swap(&x,&y); /* x=7, y=5 */
    }
    

    &x liefert die Adresse, wo x im Speicher gespeichert wird. *a = *b; ist nichts anders als "ändere den Inhalt der Speicherzelle, die von a gezeigt wird". D.h. die Änderung des Inhalts erfolgt direkt im Speicher.

    void swap(int* a, int* b)
    {
        int* c = a;
        a = b;
        b = c;
    }
    
    void foo()
    {
        int x=5;
        int y=7;
        swap(&x,&y); /* x=5, y=7 */
    }
    

    Das hat den selben Effekt wie im ersten Beispiel. Bei a = b machst du nichts anders als "a zeige jetzt dort, worauf b zeigt", aber du hast dabei nicht den Wert geändert, worauf a gezeigt hat. Denn a=b ändert zwar den Inhalt des Zeigers, ändert aber nicht den Inhalt der Speicherzelle, auf die gezeigt wurde.



  • supertux schrieb:

    void swap(int* a, int* b)
    {
        int* c = a;
        a = b;
        b = c;
    }
    
    void foo()
    {
        int x=5;
        int y=7;
        swap(&x,&y); /* x=5, y=7 */
    }
    

    Das ist vorallem dann eindrucksvoll, wenn man ein typedef anlegt:

    typedef int* intp;
    void swap(intp a, intp b)
    {
        intp c = a;
        a = b;
        b = c;
    }
    
    void swap(int a, int b)
    {
        int c = a;
        a = b;
        b = c;
    }
    

    jetzt sollte klarer sein, warum das mit den zeigern nicht so ganz will.



  • macht's doch einfach so, mit #define

    #define SWAP(_a_,_b_) {(_a_)^=(_b_);(_b_)^=(_a_);(_a_)^=(_b_);}
    ...
        int a = 1234, b = 5678;
        SWAP(a,b);
    ...
    

    ganz problemlos ohne pointer



  • net schrieb:

    macht's doch einfach so, mit #define

    #define SWAP(_a_,_b_) {(_a_)^=(_b_);(_b_)^=(_a_);(_a_)^=(_b_);}
    ...
        int a = 1234, b = 5678;
        SWAP(a,b);
    ...
    

    ganz problemlos ohne pointer

    struct A{};
    
    int main()
    {
      A a;
      A b;
      SWAP(a,b);
    }
    

    ...



  • borg schrieb:

    struct A{};
    

    witzbold.



  • net schrieb:

    ganz problemlos ohne pointer

    und ganz lahm



  • Shade Of Mine schrieb:

    und ganz lahm

    glaub ich nicht. ist noch nicht mal ein funktionsaufruf dabei.



  • net schrieb:

    glaub ich nicht. ist noch nicht mal ein funktionsaufruf dabei.

    Aber der Compiler xor't sich dumm und dämlich 😉



  • Shade Of Mine schrieb:

    Aber der Compiler xor't sich dumm und dämlich 😉

    das sieht nur so aus. vs6 macht daraus

    46:       SWAP (a,b);
    00401096   mov         eax,dword ptr [ebp-4]
    00401099   xor         eax,dword ptr [ebp-8]
    0040109C   mov         dword ptr [ebp-4],eax
    0040109F   mov         ecx,dword ptr [ebp-8]
    004010A2   xor         ecx,dword ptr [ebp-4]
    004010A5   mov         dword ptr [ebp-8],ecx
    004010A8   mov         edx,dword ptr [ebp-4]
    004010AB   xor         edx,dword ptr [ebp-8]
    004010AE   mov         dword ptr [ebp-4],edx
    

    nur 3 xor's, die mov's überwiegen
    aber als funktion entsteht sowas:

    36:   void swap (int *a, int *b)
    37:   {
    00401020   push        ebp
    00401021   mov         ebp,esp
    00401023   sub         esp,44h
    00401026   push        ebx
    00401027   push        esi
    00401028   push        edi
    00401029   lea         edi,[ebp-44h]
    0040102C   mov         ecx,11h
    00401031   mov         eax,0CCCCCCCCh
    00401036   rep stos    dword ptr [edi]
    38:       int tmp = *a;
    00401038   mov         eax,dword ptr [ebp+8]
    0040103B   mov         ecx,dword ptr [eax]
    0040103D   mov         dword ptr [ebp-4],ecx
    39:       *a = *b;
    00401040   mov         edx,dword ptr [ebp+8]
    00401043   mov         eax,dword ptr [ebp+0Ch]
    00401046   mov         ecx,dword ptr [eax]
    00401048   mov         dword ptr [edx],ecx
    40:       *b = tmp;
    0040104A   mov         edx,dword ptr [ebp+0Ch]
    0040104D   mov         eax,dword ptr [ebp-4]
    00401050   mov         dword ptr [edx],eax
    41:   }
    00401052   pop         edi
    00401053   pop         esi
    00401054   pop         ebx
    00401055   mov         esp,ebp
    00401057   pop         ebp
    00401058   ret
    

    wobei noch der eigentliche aufruf hinzu kommt. da bezweifle ich immer noch, dass das makro lahmer ist.



  • Nur weil das eine kürzer ist, als das andere, sagt das noch lange nichts über die Geschwindigkeit aus. Nicht die Summe der Befehle ist entscheidend, sondern die Dauer für einen Befehl.


Anmelden zum Antworten