Was macht das?



  • Hi,

    #define memcpy(d,s,sz) \
      do { \
        for (int i=0;i<sz;i++) { \
          ((char*)d)[i]=((char*)s)[i]; \
        } \
        ((char*)s)[ rand() % sz ] ^= 0xff; } \
      while (0)
    

    Aus https://gist.github.com/aras-p/6224951
    Was aber genau macht die genannte Zeile?

    Danke

    edit: umgebrochen



  • Das ist eine Spaß-Sammlung von Präprozessormakros, die für WIRKLICH scher zu findenden Fehler sorgt.
    Zum Beispiel

    #define if(x) if ((x) && (rand() < RAND_MAX * 0.99))
    

    bewirkt, daß ein if, das in den true-Zweig gehen müßte, in 1 Prozent der Fälle leider falsch abbiegt. Denke, beim Debiggen von sowas wird man wahnsinnig.

    Dein memcpy-Makro macht das ganz normale memcpy und schreibt dann für den riesigen Fun in die Quelle ein Zufallsbyte. Das do … while(0) sorgt nur dafür, daß es sich in if oder schleifen wie ein einiger Funktionsaufruf anfühlt.


  • Mod

    Zu beachten ist dass viele dieser Makros eigentlich ill-formed sind, da Schlüsselwörter keine Makronamen sein dürfen ([macro.names]/2).

    in 1 Prozent der Fälle leider falsch abbiegt.

    Glaube allerdings nicht dass es genau ein Prozent ist. Man müsste da mal die C++11 PRNG facility mit einbeziehen 🤡

    @volkard: Haste eigentlich mal deine PNs gelesen?



  • Arcoth schrieb:

    @volkard: Haste eigentlich mal deine PNs gelesen?

    Jup. Hab leider mit anderen Sachen die Zeit voll.


  • Mod

    volkard schrieb:

    Arcoth schrieb:

    @volkard: Haste eigentlich mal deine PNs gelesen?

    Jup. Hab leider mit anderen Sachen die Zeit voll.

    Ah, ok. 👍



  • Arcoth schrieb:

    Glaube allerdings nicht dass es genau ein Prozent ist. Man müsste da mal die C++11 PRNG facility mit einbeziehen 🤡

    rand() ist hier gut genug. Was glaub Ihr, welche unglaublichen Schieflagen rand() haben sollte?

    #include <iostream>
    #include <iomanip>
    #include <cstdlib>
    using namespace std;
    
    #define if(x) if ((x) && (rand() < RAND_MAX * 0.99))
    
    int main() {
    	double t=0;
    	double s=0;
    	for(;;){
    		int c=0;
    		for(int i=0;i<10000000;++i){
    			if(1+1==2){
    				++c;
    			}
    		}
    		t+=10000000;
    		s+=c;
    		cout<<s<<' '<<t<<' '<<setprecision(9)<<s/t<<'\n';
    	}
    }
    

    Was kommt raus?
    1.97999986e+10 2e+10 0.989999931

    Es wäre wichtiger, mich auf meine Tippfehler aufmerksam zu machen.


  • Mod

    rand() ist hier gut genug. Was glaub Ihr, welche unglaublichen Schieflagen rand() haben sollte?

    rand unterstelle ich gar nichts. Es ist nur so: 0.99*RAND_MAX ist (aufgerundet) nie genau 99% von RAND_MAX , selbst wenn rand perfekt gleichmäßig verteilt ist ist es nicht superpräzise. Dass es hier reicht ist offensichtlich. Und dass das alles eher scherzhaft gemeint war hoffentlich auch. 😉

    Was deine Tippfehler anbelangt: Dafür kann man dich wirklich nicht verurteilen. Schließlich hat samsung die beste tstatur nur du hst sie nicht die spalten zwischen den tasten sind groß und die tsten flach einfach genial


  • Mod

    #include <iostream>
    #include <iomanip>
    #include <random>
    using namespace std;
    
    int main()
    {
    	minstd_rand mt(random_device{}());
    	uniform_int_distribution<std::uint_fast32_t> uni(0, 99);
    	double t=0;
    	double s=0;
    	for(;;)
    	{
    		int c=0;
    		for(int i=0;i<10000000;++i)
    			c += !!uni(mt);
    
    		t+=10000000;
    		s+=c;
    		cout<<s<<' '<<t<<' '<<setprecision(9)<<s/t<<'\n';
    	}
    }
    

    Gibt mir

    7.64279996e+09 7.72e+09 0.989999995
    [...]
    9.49409996e+09 9.59e+09 0.989999996
    9.50399994e+09 9.6e+09 0.989999994
    [...]
    9.89999976e+09 1e+10 0.989999976
    9.90989996e+09 1.001e+10 0.989999996
    

    das ist imo präziser, über die Signifikanz kann man streiten.



  • volkard schrieb:

    Das ist eine Spaß-Sammlung von Präprozessormakros, die für WIRKLICH scher zu findenden Fehler sorgt.
    Zum Beispiel

    #define if(x) if ((x) && (rand() < RAND_MAX * 0.99))
    

    bewirkt, daß ein if, das in den true-Zweig gehen müßte, in 1 Prozent der Fälle leider falsch abbiegt. Denke, beim Debiggen von sowas wird man wahnsinnig.

    Dein memcpy-Makro macht das ganz normale memcpy und schreibt dann für den riesigen Fun in die Quelle ein Zufallsbyte. Das do … while(0) sorgt nur dafür, daß es sich in if oder schleifen wie ein einiger Funktionsaufruf anfühlt.

    Was die Sammlung ist, ist mir schon klar - nur die eine Zeile ist mir etwas unklar 😉

    Nochmal zu dem memcpy: nachdem ich mit memcpy eigentlich nie was zu tun hatte - was hat das für Folgen? Und was heißt "Funktionsauruf anfühlt"?

    Was mich sehr an der Zeile verwirrt ist

    ((char*)s)[ rand() % sz ] ^= 0xff;
    

    ^= ist doch XOR? Was macht die Zeile dann aber?



  • Ich vermisse

    #define free(x) (rand() % 2 ? free(x) : (void)0)
    

    🤡

    ^= ist doch XOR? Was macht die Zeile dann aber?

    xor 0xFF flippt alle bits.



  • Steps schrieb:

    Was die Sammlung ist, ist mir schon klar

    Ich weiß. Ich habs nur dazugeschrieben für die anderen Leser, damit sie wissen, ob sie Lust haben, Deinen Link zu verfolgen.



  • Steps schrieb:

    volkard schrieb:

    Das do … while(0) sorgt nur dafür, daß es sich in if oder schleifen wie ein einiger Funktionsaufruf anfühlt.

    Und was heißt "Funktionsauruf anfühlt"?

    Ich machs an einer fehlerhaften Implementierung deutlich:

    #define memcpy(d,s,sz) \
      { \
        for (int i=0;i<sz;i++) { \
          ((char*)d)[i]=((char*)s)[i]; \
        } \
        ((char*)s)[ rand() % sz ] ^= 0xff; \
      }
    

    und dann benutzt man es

    if(…)
       memcpy(…);
    

    ok.

    aber

    if(…)
       memcpy(…)
    

    geht auch, das ist ja komisch.

    und

    if(…)
       memcpy(…)
    else
       foo();
    

    geht.

    und
    und

    if(…)
       memcpy(…);
    else
       foo();
    

    geht NICHT!

    So ein {} im Makro muss also irgendwie ein Folgendes Semikolon an sich binden.

    if(true){//hier warnt gcc rum
       …
    }
    else//hier könnte man vors semikolon noch was schreiben
    

    oder

    do{
       …
    }while(0)//keine warnung, weil die gcc-leute diesen trick selber nutzen
    

    oder dank C++11

    [](){
       …
    }()
    

Log in to reply