Frage des Standards?



  • Hallo,
    Ich studiere derzeit Informatik und in diesem Semester beschäftigen wir uns mit C (Betriebssysteme). Ich hatte aber schon vorher ein paar Sachen in C programmiert und habe an dem, was uns beigebracht wird was auszusetzen. Es geht um folgenden Abschnitt:

    typedef struct {
      void* frame;
      int size;
      int number;
    } alloc_block;
    
    alloc_block allocs[20];
    
    int main() {
      ...
      memset(allocs, 0, sizeof(allocs));
      ...
    }
    

    Also es wird zunächst eine Struktur definiert, dann wird ein Array mit einer festgelegten Anzahl an Elementen global angelegt und im Code mit memset genullt. Meinem Verständnis nach, und da gibt mir ein lokaler Test auch Recht, nullt man mit memset in diesem Fall aber nur soviel Bytes, wie ein Zeiger auf dem System groß ist, da allocs eigentlich ein Zeiger ist und sizeof(allocs) liefert in diesem Fall die Größe eines einzelnen Zeigers. Also auf meinem 64-Bit System werden so 8 Bytes genullt und nicht die Größe einer Struktur oder das ganze Array. Bevor ich mich aber beim Übungsgruppenleiter beschwere (das wäre nicht der einzige Grund 😉 ), wollte ich wissen, ob es nicht doch noch irgendeinen neuen C-Standard gibt, der das ermöglicht (quasi ein intelligenter Compiler).
    Also: Gibt es einen Standard, der den oben gezeigten Code so kompiliert wie gewollt, also die Anweisung als memset(allocs, 0, sizeof(alloc_block) * 20) kompiliert.
    Gesucht habe ich auch, und siehe da, ein Thread in diesem Forum wo was ähnliches besprochen wird. Zu meinem Erstaunen auch wieder fehlerhaft... oder ich habe es einfach falsch verstanden?

    Wäre für etwas Hilfe dankbar 🙂

    nobody44



  • sizeof bezieht sich da die größe zur compilezeit bekannt auf allocs[20] und nicht den zeiger...



  • nobody44 schrieb:

    Meinem Verständnis nach, und da gibt mir ein lokaler Test auch Recht, nullt man mit memset in diesem Fall aber nur soviel Bytes, wie ein Zeiger auf dem System groß ist, da allocs eigentlich ein Zeiger ist und sizeof(allocs) liefert in diesem Fall die Größe eines einzelnen Zeigers.

    Was für ein Test ist das denn? Genau mit dem geposteten Code? Sonst siehe Vorredner. allocs ist eben kein Zeiger, sondern ein Array. Das verhälts sich zwar zu fast jeder Gelegenheit wie ein Zeiger, aber nicht zu jeder. Beispielsweise nicht beim sizeof-Operator.



  • #include <stdio.h>
    
    int main()
    {
      char charbuf[49];
      int intbuf[30];
    
      printf("%i\n", sizeof(charbuf));
      printf("%i\n", sizeof(intbuf));
    
      getchar(); // .. ;)
      return 0;
    }
    

    Verhalten von sizeof sollte hier dann selbsterklärend sein.



  • Skeptischer wäre ich eher warum hier überhaupt mit memset das Ding "genullt" werden soll, da statische Objekte wie eben jenes globale Array ohnehin (vor main()) entpsrechend "genullt" werden (pedantisch gesehen sogar korrekter, aber lassen wir das).



  • N'Abend,
    Tatsache...
    mein "Test" sah anders aus, ich habe nämlich einfach einen Pointer genommen und auf den Pointer habe ich sizeof angewendet. Ist irgendwo eine Auflistung wann ein Array anders behandelt wird als ein Zeiger? Ich habe eigentlich nur noch den Satz im Kopf "Arrays und Zeiger sind gleich!", und genau deswegen habe ich auch nur einen Zeiger genommen ...
    So kann man sich täuschen... ich persönlich fände es zwar besser, wenn es auch beim sizeof-Operator keinen Unterschied machen würde... dann bräuchte man sich nicht die Unterschiede merken...
    Aber gut, muss ich wohl mit leben :)...
    Danke an alle für die Hilfe

    nobody44



  • Soweit ich weiß gibt sizeof IMMER die Größe des übergebenen Objekts in Bytes zurück. Sowohl für Pointer als auch für Arrays. Bei "char array[64]" ist "array" eben doch nicht das gleiche wie &array[0] 😉



  • Ok, JETZT bin ich verwirrt...

    Soweit ich weiß gibt sizeof IMMER die Größe des übergebenen Objekts in Bytes zurück. Sowohl für Pointer als auch für Arrays.

    Ich dachte jetzt eigentlich, dass genau DAS nicht gilt...
    Sizeof liefert bei einem Array mit bekannter Größe die Bytes zurück, die durch das Array belegt sind. Bei einem Pointer liefert sizeof die Größe eines Zeigers...

    Bei "char array[64]" ist "array" eben doch nicht das gleiche wie &array[0] 😉

    ??? Erläutern bitte :)... genau das habe ich oft eingetrichtert bekommen ^^...

    Wuah... eigentlich mag ich C/C++ ja, aber in solchen Momenten kommen meine Zweifel :)...



  • nobody44 schrieb:

    Ist irgendwo eine Auflistung wann ein Array anders behandelt wird als ein Zeiger?

    6.3.2.1 Absatz 3 nennt 3 Ausnahmen:

    • Den sizeof-Operator
    • Den einstelligen &-Operator
    • Ein String-Literal, mit dem ein Array initialisiert wird.


  • Du kannst es ja leicht selbst ausprobieren:

    #include <stdio.h>
    
    typedef struct chkpnt {
      unsigned *value;
    } chkpnt;
    
    typedef struct chkarr {
      unsigned value[5];
    } chkarr;
    
    int main()
    {
      printf("%i == %i?\n", sizeof(chkpnt), sizeof(chkarr));
    }
    

    Ein Array trickst also nicht den sizeof-Operator aus, es ist effektiv grösser¹ als ein Pointer.

    Eine ausführliche Erklärung siehst du da: http://c-faq.com/aryptr/aryptr2.html

    ¹: oder gleich in einem ein-elementrigen Array.



  • Keine Panik, ist kein so schwieriges Thema:

    void f(int* p); // Prototyp
    void g(int* p, int size); // Prototyp
    void h()
    {
      int intbuf[30];
      printf("%i\n", sizeof(intbuf)); // hier ist die Größe bekannt (auf 32 Bit Systemen 120 Byte)
      f(p);
      g(&p[0],30); // &p[0] ist äquivalent
    }
    void f(int* p)
    {
      // hier hat man keine Chance, auf die Größe von p zu schließen, p zeigt auf intbuf[0],
      // bei char-Arrays wird der String daher durch '\0' abgeschlossen, Funktionen wie strcpy hätten ansonsten keine Möglichkeit, die Größe herauszufinden.
    }
    void g(int* p, int size)
    {
      memset(p,0,sizeof(int)*size); // so geht es auch über Zeiger
    }
    


  • anybody schrieb:

    Du kannst es ja leicht selbst ausprobieren:
    ...

    Das hatte ich schon verstanden :)...

    Um es nochmal zu verdeutlichen:

    typedef struct {
       int p;
       char plol;
    } st;
    
    int main() {
       st* pointer = malloc(sizeof(st) * 10);
       st array[10];
       printf("pointer: %i, array: %i\n", sizeof(pointer), sizeof(array));
       return 0;
    }
    

    Ich hatte in diesem Fall gedacht, dass sizeof zwei gleiche Werte zurückgibt, weil array nach meinem Verständnis ein "konstanter Zeiger" (bitte nirgendwo zitieren, ich weiß dass es nicht korrekt ausgedrückt ist 🙂 ) ist, pointer ebenfalls ein Zeiger, also müssten beide 4 bzw. 8 Bytes groß sein.
    Gut... jetzt weiß ich, dass sizeof bei Arrays, bei denen die Anzahl der Elemente zur Kompilierzeit bekannt ist, die Größe des gesamten Arrays liefert.

    g(&p[0],30); // &p[0] ist äquivalent
    

    6.3.2.1 Absatz 3 nennt 3 Ausnahmen:
    Den einstelligen &-Operator

    Ihr meint bestimmt das selbe, aber es kommt anders rüber... was ist denn beim einstelligen &-Operator bei einem Array anders als beim Pointer?

    Danke für die Aufklärung für dieses Thema... Pointer in C sind wohl nicht zu Unrecht gefährlich... und so eine Erklärung hätte ich in meiner Uni nicht bekommen :)...

    nobody44



  • nobody44 schrieb:

    g(&p[0],30); // &p[0] ist äquivalent
    

    6.3.2.1 Absatz 3 nennt 3 Ausnahmen:
    Den einstelligen &-Operator

    Ihr meint bestimmt das selbe, aber es kommt anders rüber... was ist denn beim einstelligen &-Operator bei einem Array anders als beim Pointer?

    Dein Beispiel hat nichts mit der Frage zu tun. Natürlich musst Du den &-Operator auch auf das fragliche Array / den Zeiger anwenden. Also:

    int a[10];
    int *p;
    

    Dann ist &p vom Typ int**, &a vom Typ int[10]*.



  • SG1 schrieb:

    &a vom Typ int[10]*.

    int (*)[10] </klugscheiß>


Anmelden zum Antworten