Warum gibt es im C-Standard kein “recalloc”?

Lesezeit: 6 Minuten

Jeder weiss das:

  • realloc ändert die Größe eines vorhandenen Speicherblocks oder kopiert ihn in einen größeren Block.
  • calloc stellt sicher, dass der Speicher auf Null gesetzt wird und schützt vor arithmetischen Überläufen und ist im Allgemeinen auf große Arrays ausgerichtet.

Warum bietet der C-Standard keine Funktion wie die folgende, die beides kombiniert?

void *recalloc(void *ptr, size_t num, size_t size);

Wäre es nicht nützlich, um die Größe riesiger Hash-Tabellen oder benutzerdefinierter Speicherpools zu ändern?

  • Wenn Sie einfach alles auf Null setzen, macht es keinen Sinn, die Größe zu ändern – geben Sie einfach den alten Block frei und rufen Sie dann einen neuen Block auf.

    – PaulR

    12. Februar 2015 um 20:52 Uhr


  • @PaulR: Vermutlich würde es nur den neuen Speicher auf Null setzen (oder besser gesagt sicherstellen, dass es so ist auf Null gesetzt).

    – Matt

    12. Februar 2015 um 20:53 Uhr


  • Der Zweck der Standardbibliothek besteht nicht darin, einen reichhaltigen Satz cooler Funktionen bereitzustellen. Es soll einen wesentlichen Satz von Bausteinen bereitstellen, aus denen Sie Ihre eigenen coolen Funktionen bauen können. Ihr Vorschlag für Recalloc wäre trivial zu schreiben und sollte daher nicht von der Standardbibliothek bereitgestellt werden.

    – abelenky

    12. Februar 2015 um 20:57 Uhr

  • Scheint mir alles in allem ein fairer Vorschlag zu sein

    – MM

    12. Februar 2015 um 21:09 Uhr

  • calloc() hat eine andere Funktion, die malloc() funktioniert nicht: in obskuren Systemen wie DOS: die Möglichkeit, ein Array größer als zuzuweisen SIZE_MAX. So könnte Code calloc(60000u, sizeof (double))sogar wenn size_t war 16-Bit. Ich habe mich über die C-Konformität gewundert – aber es scheint richtig zu sein.

    – chux – Wiedereinsetzung von Monica

    12. Februar 2015 um 21:42 Uhr

Generell ist in C der Punkt der Standardbibliothek nicht um eine Vielzahl cooler Funktionen bereitzustellen. Es ist eine bereitzustellen essentiell Satz von Bausteinen, aus denen Sie Ihre eigenen coolen Funktionen bauen können.

Ihr Vorschlag für recalloc wäre trivial zu schreiben und sollte daher nicht von der Standardbibliothek bereitgestellt werden.

Andere Sprachen verfolgen einen anderen Ansatz: C# und Java haben superreiche Bibliotheken, die selbst komplizierte Aufgaben trivial machen. Aber sie sind mit einem enormen Overhead verbunden. C hat einen minimalen Overhead, und das hilft dabei, es auf alle Arten von eingebetteten Geräten portierbar zu machen.

  • Sie müssten alles über den virtuellen Speicher des Systems wissen, um eine solche Funktion effizient schreiben zu können, ohne sie aufrufen zu müssen memset.

    – Matt

    12. Februar 2015 um 21:00 Uhr

  • @abelenky Worauf er hinaus will, ist, dass einige Betriebssysteme übernehmen calloc Seiten aus einem anderen Pool als malloc Seiten (wenn möglich) und der Calloc verwendet Lazy Allocation mit Copy-on-Write von einer Seite aus nur Nullen. Deshalb calloc unter Linux kann schneller sein als malloc (und viel schneller als malloc gefolgt von memset).

    – MM

    12. Februar 2015 um 21:03 Uhr

  • @abelenky: Sie müssten den gesamten Rest des Blocks durchlaufen, anstatt sich auf voreingestellten Copy-on-Write-Speicher zu verlassen.

    – Matt

    12. Februar 2015 um 21:03 Uhr

  • @MattMcNabb: Hatte keiner size_tund viele andere Dinge, die jeder benutzt.

    – Matt

    12. Februar 2015 um 21:08 Uhr

  • @abelenky Ich würde diese vorgeschlagene Version nicht sagen recalloc wäre trivial zu schreiben, auch mit memset: für recalloc Um als nullerweiterte Kopie zu arbeiten, müssten Sie die anfängliche Größe des Speichers im Auge behalten. IMHO, die Begründung dahinter realloc war es, den Benutzer davon abzuhalten, die Größe des zugewiesenen Speichers zu verfolgen. Wenn die Standardbibliothek nur wesentliche Funktionen bereitstellen sollte, wäre sie nie eingeführt worden realloc in erster Linie, da es leicht in einer bedingten malloc-copy-free-Anweisung ausgedrückt werden kann.

    – aprelew

    18. September 2019 um 22:37 Uhr

Ich nehme an, Sie sind daran interessiert, nur den neuen Teil des Arrays auf Null zu setzen:

Nicht jeder Speicherzuordner weiß, wie viel Speicher Sie in einem Array verwenden. zum Beispiel, wenn ich mache:

char* foo = malloc(1);

foo weist jetzt darauf hin mindestens ein Stück Speicher 1 Byte groß. Die meisten Allokatoren weisen jedoch viel mehr als 1 Byte zu (z. B. 8, um die Ausrichtung beizubehalten).

Dies kann auch bei anderen Zuweisungen passieren. Der Speicherzuordner wird zuordnen mindestens so viel Speicher, wie Sie wünschen, wenn auch oft nur ein bisschen mehr.

Und es ist dieser “nur ein bisschen mehr” Teil, der die Dinge vermasselt (zusätzlich zu anderen Faktoren, die dies schwierig machen). Weil wir nicht wissen, ob es nützliches Gedächtnis ist oder nicht. Wenn es nur Polsterung ist, und du recalloc es, und der Allocator setzt es nicht auf Null, dann haben Sie jetzt “neuen” Speicher, der einige Nicht-Null-Werte enthält.

Was wäre zum Beispiel wenn ich recalloc foo damit es auf einen neuen Puffer zeigt, der mindestens 2 Bytes groß ist. Wird dieses zusätzliche Byte auf Null gesetzt? Oder nicht? Das sollte es sein, aber beachten Sie, dass die ursprüngliche Zuweisung uns 8 Bytes gegeben hat, sodass durch die Neuzuweisung kein neuer Speicher zugewiesen wird. Soweit der Zuordner sehen kann, muss er keinen Speicher auf Null setzen (weil es keinen “neuen” Speicher auf Null gibt). Was zu einem schwerwiegenden Fehler in unserem Code führen könnte.

  • Deshalb wäre eine solche Funktion nur für große Speicherblöcke sinnvoll.

    – Matt

    12. Februar 2015 um 21:02 Uhr

  • @Cornstalks: Nun, dann müsste es eine Einschränkung geben, dass es nur mit zuvor zugewiesenem Speicher ordnungsgemäß funktioniert calloc oder selbst.

    – Matt

    12. Februar 2015 um 21:07 Uhr

  • @Matt: Das könntest du tun, aber jetzt malst du dich in eine seltsame Ecke und die Nützlichkeit davon recalloc Funktion nimmt ab. Sie könnten es zum Laufen bringen, indem Sie mehr und mehr willkürliche Einschränkungen hinzufügen, aber irgendwann (eher früher als später) ist es einfach einfacher, vom Benutzer zu verlangen, den Speicher im Auge zu behalten und den neuen Speicher nach a auf Null zu setzen realloc.

    – Maisstängel

    12. Februar 2015 um 21:09 Uhr

  • @Matt Mein Vorschlag war – klarer – eine Calloc-Neuzuweisung von 100001, dann 100008 und dann zurück zu 100001 und dann wiederhole das. Die wahre Blockgröße hat sich nie geändert. Aber ich sehe, dass die aufgefüllten Bytes beim Verringern null sein könnten – wodurch die Notwendigkeit, die vorherige Anforderungsgröße beizubehalten, negiert wird. Danke für die Herausforderung.

    – chux – Wiedereinsetzung von Monica

    12. Februar 2015 um 21:24 Uhr


  • @Cornstalks Was den Standard betrifft, gibt es keine zusätzlichen Bytes. Das Zuweisen zusätzlicher Bytes zum “Beibehalten der Ausrichtung” ist etwas, was eine bestimmte Implementierung tun könnte, genauso gut wie es den angeforderten vs. den ausgegebenen Speicher verfolgen könnte. Wie ich sagte, recalloc wird die Implementierung zwingen, diese zusätzlichen Bytes zu löschen, sicher. So wie Ausrichtungsanforderungen auf einigen Architekturen die Implementierung zwingen, diese zusätzlichen Bytes überhaupt zuzuweisen.

    – aprelew

    24. September 2019 um 16:04 Uhr

1443670cookie-checkWarum gibt es im C-Standard kein “recalloc”?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy