Warum werden bestimmte C-Datentypen in mehr als einer Standard-Header-Datei deklariert?

Lesezeit: 7 Minuten

Benutzer-Avatar
Astaroth

Das schreibt zum Beispiel C11 vor size_t sollte in den folgenden Header-Dateien deklariert werden:

  • stddef.h
  • stdio.h
  • stdlib.h
  • string.h
  • Zeit.h
  • uchar.h
  • wchar.h

Beim Lesen von C11 habe ich festgestellt, dass viele andere Datentypen in mehr als einer Standard-Header-Datei deklariert sind.

Fragen

  1. Sagen wir im Fall von size_t. Warum nicht einfach rein stddef.h der Einfachheit halber?
  2. Nehmen wir an, ein C-Compiler implementiert size_t in diesen Header-Dateien. Haben sie garantiert dieselbe Definition in diesen Header-Dateien?

  • size_t wurde in c89 / c90 / K&R2 eingeführt. Es war bereits zu spät, um zu erkennen, dass es sich tatsächlich um einen grundlegenden Typ (intern für die Sprache und den Compiler) der meisten Header handelte. benötigen es, und die Header, die es benötigen, liefern eine Definition dafür

    – joop

    15. August 2014 um 12:25 Uhr

Benutzer-Avatar
Trient

Als Beispiel für eine deklarierte Funktion in stdio.h Das erfordert, dass size_t vordeklariert wird snprintf(). Wenn Sie es in Ihrem Code verwenden möchten, müssen Sie es nur tun #include <stdio.h>. Wenn size_t nur in deklariert wurde stddef.hSie müssten

#include <stddef.h>
#include <stdio.h>

Nicht nur das, sondern seitdem stdio.h erklärt snprintf ob Sie es verwenden oder nicht, Sie müssten es einschließen beide Dateien jeder Zeit, die Sie brauchten irgendetwas in stdio.h um Compilerfehler zu vermeiden; stdio.h hätte eine künstliche Abhängigkeit stddef.h. Das führt dazu, dass Ihr Quellcode länger und spröder wird (beachten Sie, dass es auch brechen würde, wenn Sie die Reihenfolge der beiden Direktiven umkehren). Stattdessen schreiben wir Header-Dateien so, dass sie alleine stehen und nicht von anderen Headern abhängen, und das hat das C-Standardisierungskomitee für die Standardbibliothek beschlossen.

  • Das ist glaubwürdig und erscheint auf den ersten Blick logisch, ist es aber wirklich nicht. size_t ist eine Typedef für einen bestimmten vordefinierten Typ, und Systemheader sind systemspezifisch. Auf einem System, wo size_t ist ein typedef für zB unsigned intgäbe es kein Problem (keine Schwierigkeit und kein Konformitätsproblem), wenn die Implementierung deklariert snprintf als nehmen unsigned int Anstatt von size_tsodass die Typedef nicht benötigt wird.

    Benutzer743382

    15. August 2014 um 23:39 Uhr


  • @trentcl, Was ist falsch an der Abhängigkeit zwischen Header-Dateien? Tatsächlich habe ich in C-Standard-Header-Dateien von GCC viele Abhängigkeiten zwischen ihnen gesehen, wenn bestimmte Compiler-Direktiven gesetzt sind. Könnten Sie mir für Ihre Aussage, dass Header-Dateien so geschrieben sind, dass jede von ihnen unabhängig ist, eine Referenz dafür geben?

    – Astaroth

    16. August 2014 um 14:06 Uhr


  • @hvd: Standard-Header-Dateien müssen nicht in C geschrieben sein oder überhaupt existieren, aber normalerweise existieren sie und sind in C geschrieben. Wie Klas zuvor festgestellt hat, ist es oft möglich, size_t durch Setzen einer Compiler-Option auf eine andere Größe zu ändern — wie würden Sie dann stdio.h schreiben? Der Standard ist aus den Gründen, die ich gegeben habe, so geschrieben, wie er ist. Was es Genehmigungen ist eine ganz andere Sache.

    – Trient

    17. August 2014 um 11:03 Uhr

  • @Astaroth, was an Header-Datei-Abhängigkeiten falsch ist, ist, dass es den Code länger und spröder macht, ohne dass dies von Vorteil ist. Ihr Vorschlag würde, wenn ich ihn wie die meisten Implementierungen implementieren würde, eine Definition von size_t erfordern, im Kundencodevor jedem #include <stdio.h>. Das ist überflüssig und bricht (praktisch alles) vor C99 C, wo das nicht nötig war. Stellen Sie daher am besten sicher, dass Header-Dateien alle Informationen enthalten, die zur Verwendung der darin enthaltenen Dinge erforderlich sind. Ich weiß nicht, auf welche “besonderen Compiler-Direktiven” Sie sich beziehen; kannst du ein beispiel geben?

    – Trient

    17. August 2014 um 11:15 Uhr

  • @trentcl, +1 für Ihre Aussage “es bricht (praktisch alles) vor C99 C”, aber für die Rendundanz, stdio.h beinhalten könnte stddef.h, oder? Übrigens, ich habe GCC 4.8 von MinGW mit Code::Block als IDE verwendet. Ich habe versucht zu verwenden snprintf() in einem einfachen Code mit nur stdio.h ist enthalten, und GCC kompiliert es fein. Im stdio.h von meinem GCC gibt es #include <stddef.h> unter #ifndef RC_INVOKED

    – Astaroth

    17. August 2014 um 12:13 Uhr

Sagen wir im Fall von size_t. Warum der Einfachheit halber nicht einfach in stddef.h?

Der Typ wird bei der Deklaration von Funktionen in all diesen Dateien verwendet. Wenn es nicht deklariert wurde <stdio.h> Sie würden einen Kompilierungsfehler erhalten, wenn Sie nicht zuerst einschließen <stddef.h>.

Nehmen wir an, ein C-Compiler implementiert size_t in diesen Header-Dateien. Haben sie garantiert dieselbe Definition in diesen Header-Dateien?

Ja, sie werden die gleiche Definition haben. Normalerweise wird der Wert an einer einzigen Stelle in einer separaten Include-Datei definiert, die von den anderen eingebunden wird.

In einigen Fällen kann es möglich sein, die Definition mit Compileroptionen oder -definitionen zu modifizieren, beispielsweise kann ein Compiler, der eine 32/64-Bit-Kompilierung zulässt, definieren size_t als 32- oder 64-Bit-Entität ohne Vorzeichen, abhängig vom Ziel, das auf der Compiler-Befehlszeile definiert wurde.

  • Oder stdio.h beinhalten könnte stddef.h.

    – Benutzer253751

    16. August 2014 um 3:45 Uhr

Benutzer-Avatar
Tim Post

Es gibt einen feinen Unterschied zwischen durch und in – Eine Implementierung kann völlig frei definiert werden size_t in einem einzigen Header, solange es definiert ist wenn die angegebenen Header sind inklusive. Dafür haben Sie also zwei Möglichkeiten:

  1. Definieren size_t in jedem einzelnen und wickeln Sie jeden ein, einschließlich Wachen
  2. Definieren Sie es in einer einzigen Datei und packen Sie es in include guards ein

Und ja, size_t muss wie angegeben definiert werden, was (glibc):

typedef unsigned long size_t;

oder

typedef unsigned int size_t

Sie sagen nicht, dass Sie bei Verstand sein müssen, sie sagen nur, dass es zu dem Zeitpunkt definiert werden muss, an dem jemand einen dieser Header einfügt, weil sie davon abhängen, dass es definiert wird und unabhängig verwendet werden kann. Einfach ausgedrückt, wenn Sie etwas abhängig definieren size_tdann size_t müssen erst (vorher) definiert werden.

Wie (oder besser gesagt wo) Sie es tun, hängt von Ihrer Implementierung ab.

  • size_t ist nicht garantiert identisch mit unsigned long. Und ist nicht auf LLP64-Implementierungen.

    – dan04

    15. August 2014 um 12:59 Uhr

  • Ich bin neu in C. Ich dachte nur, was ist, wenn ein C-Compiler deklariert size_t in einem weniger beliebten Header? Nehmen wir an, es ist nur in deklariert wchar.hdie uns sicherlich dazu bringen, einen Versuch und Irrtum zu machen, um herauszufinden, wo size_t deklariert ist, oder noch schlimmer, wir brauchen ein grep-ähnliches Werkzeug nur für eine triviale Sache. Für C-Compiler-Entwickler bedeutet es eine einfachere Wartung, wenn es nicht in einem einzigen Header deklariert wurde, da es viele andere Typen als gibt size_t das auch in einer Situation, die ich gerade erwähnt habe? Ich bin gespannt, weil ich das in Delphi und Java nicht gesehen habe.

    – Astaroth

    15. August 2014 um 14:07 Uhr


Zunächst einmal, wenn man a #include <stdio.h> Es ist nicht erforderlich, dass tatsächlich irgendwo eine Datei mit dem Namen stdio.h existiert oder dass der Compiler irgendetwas mit einer solchen Datei macht. Vielmehr ist die Anforderung, dass eine solche Leitung alle Identifikatoren verursachen muss, die als zugeordnet angegeben sind <stdio.h> nach Spezifikation zu definieren. Es wäre vollkommen legitim für einen Compiler, der sah #include <stdio.h> Aktivieren Sie einfach die Verwendung bestimmter Bezeichner, die im Compiler fest verdrahtet wurden. Denn der einfachste Weg für Compiler-Anbieter, Dinge so zu verhalten, wie es die Spezifikation erfordert, ist zu haben #include <stdio.h> Direktiven führen den Text einer Datei aus stdio.h durch den Präprozessor, das machen viele Compiler, aber das ist nicht erforderlich.

Wenn die Spezifikation “Dateien” auflistet, wo size_t deklariert werden sollte, was es wirklich sagt, ist, dass ein #include Direktive, die eine dieser Dateien benennt, sollte diese Kennung im globalen Bereich erstellen. Dies könnte dadurch erreicht werden, dass Dateien mit allen aufgelisteten Namen eine Definition von enthalten size_toder durch haben size_t in den Compiler eingebaut werden, sondern nur das Aktivieren der eingebauten Definition des Compilers sieht a #include Direktive mit einem der angegebenen Namen.

1350840cookie-checkWarum werden bestimmte C-Datentypen in mehr als einer Standard-Header-Datei deklariert?

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

Privacy policy