Funktionsweise und Geschwindigkeit von sizeof



  • Hallo!

    Könnte mir jemand erklären wo und wie sizeof an die Daten für die Objektgrößen gelangt? Ich bin nämlich einerseits am Überlegen wie es genau funktioniert und andererseits ob dieser Operator kostspielig im Bezug auf Performanz ist.

    // Sinnfreier Code
    struct Foo
    {
        int  m_Value;
        char m_Char[100];
        long m_Foo;
    };
    
    void Bar(void)
    {
       Foo  f;
       char pBuffer[5000];
    
       for(int i = 0, pos = 0; i < 100; i++, pos += sizeof(Foo))
       {
          memcpy(pBuffer + pos, &f, sizeof(Foo));
       }   
    };
    

    Wäre es sinnvoller die Größe von sizeof einer Variablen zu speichern und dann diesen Wert zu verwenden oder kostet ein sizeof Aufruf nichts, so dass es egal ist?



  • hola

    'sizeof' wird zur compiletime ausgewertet. ist also zur laufzeit schon ein konstanter wert.

    Meep Meep



  • Meep Meep schrieb:

    'sizeof' wird zur compiletime ausgewertet. ist also zur laufzeit schon ein konstanter wert.Meep Meep

    Gut. Aber sizeof muss dann ja in einer Art Tabelle nachschauen wie groß das Objekt ist. Kann man sagen ob das länger dauert als eine Variable abzufragen?



  • re

    der ausdruck sizeof(int) wird sozusagen im sourcecode durch eine konstante ersetzt. naiv gesehen wuerde das folgend aussehen

    int mein_int = 10 * sizeof(int);
    

    daraus wird bei der kompilierung

    int mein_int = 10 * 4; // vorausgesetzt das sizeof(int) 4 ergibt
    

    Meep Meep



  • Besten Dank auch.



  • Meep Meep schrieb:

    daraus wird bei der kompilierung

    int mein_int = 10 * 4; // vorausgesetzt das sizeof(int) 4 ergibt
    

    Falsch! Daraus wird:

    int mein_int = 40; // vorausgesetzt das sizeof(int) 4 ergibt
    


  • asdfasdfasdf schrieb:

    Meep Meep schrieb:

    daraus wird bei der kompilierung

    int mein_int = 10 * 4; // vorausgesetzt das sizeof(int) 4 ergibt
    

    Falsch! Daraus wird:

    int mein_int = 40; // vorausgesetzt das sizeof(int) 4 ergibt
    

    Und was macht der Compiler aus:

    float f = 10.0 * sizeof(int);
    

    ?

    Besonders wenn es ein Cross-Compiler ist der die Floating-Point-Bibliothek des Targets nicht kennt und womöglich auf Nicht-Optimieren eingestellt ist?



  • @HaJo
    Hör blos auf damit dir über solche Kleinigkeiten Gedanken zu machen! Microoptimierungen sind die Zeit nicht wert, die du darein investierst und am Ende schreibst du noch schrecklichen Code, weil du glaubst du sparst nen paar ns mit irgend einem gefrickel (wobei so etwas oft sogar dazu führt, dass der Code langsamer ist der generiert wird 🙄)

    Microoptimierungen geht man erst an, wenn man in einer Situation ist, wo man wirklich alles rausholen muss und schon alles andere optimiert hat und allein von der Frage kann man sehen, dass _du_ nicht in so einer Situation bist!

    * "More computing sins are committed in the name of efficiency (without necessarily achieving it) than for any other single reason - including blind stupidity.” - W.A. Wulf
    * "permature optimization is the root of all evil" - C. A. R. Hoare



  • "permature optimization is the root of all evil"

    kann man gar nicht deutlich genug machen 😃



  • thordk schrieb:

    "permature optimization is the root of all evil"

    kann man gar nicht deutlich genug machen 😃

    Ich mag ja gerne der Abwandlung durch Knuth zustimmen. Aber das könnte in dem Fall schnell missinterpretiert werden. Also lassen wir es bei der Aussage 😉



  • Zu meiner Verteidigung: 😕

    Erstens wollte ich einfach nur die Funktionsweise von sizeof erfragen, da weder eines der (anderen) C++ Bücher mir Auskunft gibt noch Bjarne in seinem Werk ein Wort darüber verliert. Würde sizeof sich die Werte zur Laufzeit irgendwo holen, wäre es meiner Meinung nach völlig i.O. den Wert zwischenzuspeichern.

    Hat gleiche Gründe wie im folgendem Beispiel:

    for(size_t i = 0; i < size() - 1; i++)
      ;
    
    // Ich würde es so machen
    size_t max = size() - 1;
    for(size_t i = 0; i < max; i++)
      ;
    }
    


  • einige optimierende compiler machen des automatisch



  • r0nny schrieb:

    einige optimierende compiler machen des automatisch

    Was? Den Aufruf von size() aus der Schleife rausziehen? (wenn ja, dürfte der Compiler nicht standardkonform sein - schließlich weiß er nicht, ob der Aufurf möglicherweise beabsichtigte Nebeneffekte hat (oder die Größe sich zwischendurch ändern könnte))



  • Wenn size() inline implementiert ist alles kein Problem.



  • CStoll schrieb:

    r0nny schrieb:

    einige optimierende compiler machen des automatisch

    Was? Den Aufruf von size() aus der Schleife rausziehen? (wenn ja, dürfte der Compiler nicht standardkonform sein - schließlich weiß er nicht, ob der Aufurf möglicherweise beabsichtigte Nebeneffekte hat (oder die Größe sich zwischendurch ändern könnte))

    Naja, size() ist für STL-Container z.B. const. Einige Compiler kennen weitere Funktionsattribute, wie __pure__ und änhnliche, die dem Compiler zusichern, dass die Funktion keine Seiteneffekte hat. Wenn nun der Compiler dies weiß und außerdem feststellt, dass der Code in der Schleife den Container ebenfalls nur lesend benutzt, kann er den Aufruf von size() aus der Schleife rausziehen.

    Andererseits ist size() bei den meisten C++-Bibliotheken eine inline-Funktion, die einfach einen Wert zurückgibt, das kann der Compiler also ebenfalls sehr schön optimieren.



  • Das Thema hatten wir doch neulich im C-Board 😉 (OK, da ging's um strlen(), aber das Prinzip ist das gleiche)

    Der Compiler darf zwar die inline-Definition auseinandernehmen und den Aufruf v.size() durch (z.B.) v._Last-v._First ersetzen, aber er darf ihn nicht aus der Schleife rausziehen. Denn erstens darf auch eine const-Methode Nebeneffekte haben (zwar nicht auf die Member des Objekts, aber auf den Rest der Welt ;)) und zweitens gibt es noch Möglichkeiten, über Aliasing den Container mit einem anderen Namen anzusprechen (in Multi-Threading-Umgebungen besteht sogar die Chance, daß sich die Containergröße innerhalb einer leeren Schleife ändert ;)).



  • richtig, aber an der stelle würde auch jeder nen bösen fehler bekommen, der die werte von hand rauszieht. Ist es dann nicht generell besser stattdessen mit iteratoren zu arbeiten? sie tun ja am ende nur das, was auch die zählvariable machen würde, nur mit dem unterschied dass man mit einem konstanten wert vergleicht.



  • Durchaus möglich (vor allem ist ein Durchlaufen per Iterator auch für Container geeignet, die keinen Direktzugriff per Index bieten), aber mitunter möchte man einen vector<> auch als Array betrachten.

    (und size() hat laut Standard eine konstante Laufzeit und ist idR inline implementiert, also sollte sich der Aufruf nur minimal auf die Geschwindigkeit auswirken - davon abgesehen können Iteratoren zwischendurch auch ungültig werden, wenn du mist baust ;))



  • otze schrieb:

    nur mit dem unterschied dass man mit einem konstanten wert vergleicht.

    Bei Iteratoren vergleicht man idR mit dem Ergebnis von end(). Das ist dasselbe in grün.



  • CStoll schrieb:

    Das Thema hatten wir doch neulich im C-Board 😉 (OK, da ging's um strlen(), aber das Prinzip ist das gleiche)

    Der Compiler darf zwar die inline-Definition auseinandernehmen und den Aufruf v.size() durch (z.B.) v._Last-v._First ersetzen, aber er darf ihn nicht aus der Schleife rausziehen. Denn erstens darf auch eine const-Methode Nebeneffekte haben (zwar nicht auf die Member des Objekts, aber auf den Rest der Welt ;)) und zweitens gibt es noch Möglichkeiten, über Aliasing den Container mit einem anderen Namen anzusprechen (in Multi-Threading-Umgebungen besteht sogar die Chance, daß sich die Containergröße innerhalb einer leeren Schleife ändert ;)).

    WENN der Compiler aliasing ausschliessen kann (und das geht in vielen Fällen), und WENN alles andere was aufgerufen wird inline ist, dann kann er den Aufruf von size() u.U. trotzdem rausziehen.

    Auf Threads darf und wird der Compiler übrigens scheissen, denn darum hat sich gefälligst der Programmierer zu kümmern!
    Versuch' es mal selbst, mach ne Schleife "while (!blah);" und setz blah dann von aussen (=aus einem anderen Thread). Die Schleife wird in nem optimierten Build nie terminieren!


Anmelden zum Antworten