Frage

Bis vor kurzem hatte ich die Entscheidung von den meisten System -Implementierern/Anbietern in Betracht gezogen, um einfach zu bleiben int 32-Bit sogar auf 64-Bit-Maschinen eine Art zweckmäßige Warze. Mit modernen C99-Typengröße (Typengröße (Typen) (int32_t und uint32_t, usw.) Die Notwendigkeit, dass es einen Standardgeistentyp jeder Größe 8, 16, 32 und 64 gibt, verschwindet meistens, und es scheint wie int könnte genauso gut 64-Bit gemacht werden.

Die größte wirkliche Folge der Größe der Ebene int In C kommt von der Tatsache, dass C im Wesentlichen keine Arithmetik auf kleineren alsint Typen. Insbesondere wenn, wenn int ist größer als 32-Bit, das Ergebnis einer Arithmetik auf uint32_t Werte haben Typ signed int, was ziemlich beunruhigend ist.

Ist das ein guter Grund zu behalten? int permanent auf 32-Bit auf reale Implementierungen festgelegt? Ich lehne mich dazu, ja zu sagen. Es scheint mir, als könnte es eine riesige Klasse von Verwendungsnutzungen geben uint32_t welche brechen wann int ist größer als 32 Bit. Selbst wenn Sie den unären minus oder bitweisen Komplement -Betreiber anwenden, wird gefährlich uint32_t.

Natürlich gelten die gleichen Probleme für uint16_t und uint8_t Bei aktuellen Implementierungen, aber jeder scheint sich der Kenntnis zu stellen und sie als "kleiner als kleiner als zu behandeln.int"Typen.

War es hilfreich?

Lösung

Wie Sie sagen, denke ich, dass die Beförderungsregeln wirklich der Mörder sind. uint32_t würde dann fördern zu int Und plötzlich hätten Sie eine Arithmetik unterschrieben, bei der fast jeder nicht signiert erwartet.

Dies wäre größtenteils an Orten versteckt, an denen Sie nur arithmetisch machen und einem zurückzuweisen uint32_t. Aber es könnte tödlich an Orten sein, an denen Sie mit Konstanten verglichen werden. Ob Code, der sich auf solche Vergleiche stützt, ohne eine explizite Besetzung zu machen, ist vernünftig, ich weiß es nicht. Gusskonstanten mögen (uint32_t)1 kann ziemlich langweilig werden. Ich persönlich benutze zumindest immer das Suffix U Für Konstanten, die ich nicht signiert sein möchte, aber dies ist bereits nicht so lesbar, wie ich möchte.

Denken Sie auch daran, dass uint32_t usw. werden nicht garantiert existieren. Nicht mal uint8_t. Die Durchsetzung davon ist eine Erweiterung von POSIX. In diesem Sinne ist C als Sprache weit davon entfernt, diesen Schritt zu bewegen.

Andere Tipps

"Angemessener Code" ...

Nun ... die Sache mit der Entwicklung ist, du schreibst und repariere sie und dann funktioniert es ... und dann hörst du auf!

Und vielleicht wurden Sie viel verbrannt, damit Sie in den sicheren Bereichen bestimmte Funktionen gut bleiben und vielleicht nicht verbrannt wurden dieser besondere Weg Sie wissen also nicht, dass Sie sich auf etwas verlassen, das sich irgendwie verändern könnte.

Oder sogar dass Sie sich auf einen Fehler verlassen.

Bei Old Mac 68000 -Compilern war int 16 Bit und lang 32 Jahre alt. Aber selbst dann nahm die meisten vorhandenen C -Code an, dass ein INT 32 betrug. Daher würde der typische Code, den Sie in einer Newsgroup gefunden haben, nicht funktionieren. (Oh, und Mac hatte kein Printf, aber ich schweife ab.)

Also, was ich mache, ist, ja, wenn Sie sich ändern irgendetwas, Dann werden einige Dinge brechen.

Mit modernen C99-Typen-Größe (int32_t und uint32_t usw.) müssen die Notwendigkeit eines Standardgeistyps jeder Größe 8, 16, 32 und 64 hauptsächlich verschwinden.

C99 hat Typedefs mit fester Größe, keine Typ mit fester Größe. Die nativen C -Ganzzahltypen sind immer noch char, short, int, long, und long long. Sie sind immer noch relevant.

Das Problem mit ILP64 ist, dass es eine große Nichtübereinstimmung zwischen C -Typen und C99 -Typedefs hat.

  • int8_t = char
  • int16_t = kurz
  • int32_t = Nicht standardmäßiger Typ
  • int64_t = int, lang oder lang lang

Aus 64-Bit-Programmiermodelle: Warum LP64?:

Leider bietet das ILP64-Modell keine natürliche Möglichkeit, 32-Bit-Datentypen zu beschreiben und muss auf nicht portable Konstrukte wie z. __int32 solche Typen zu beschreiben. Dies führt wahrscheinlich zu praktischen Problemen bei der Erzeugung von Code, die sowohl auf 32 als auch auf 64 -Bit #ifdef Konstruktionen. Es war möglich, große Mengen an Code in LP64 -Modelle zu portieren, ohne solche Änderungen vorzunehmen, während die Investitionen in Datensätze beibehalten werden, selbst in Fällen, in denen die Typisierungsinformationen von der Anwendung nicht extern sichtbar wurden.

Dec Alpha und OSF/1 Unix war eine der ersten 64-Bit-Versionen von UNIX und verwendete 64-Bit-Ganzzahlen-eine ILP64 int, long und Zeiger waren alle 64-Bit-Mengen). Es verursachte viele Probleme.

Ein Problem, das ich nicht gesehen habe - weshalb ich so lange überhaupt antworte - ist, dass wenn Sie eine 64 -Bit haben int, für welche Größe verwenden Sie short? Beide 16 Bits (der klassische, verändern nichts Ansatz short sollte halb so lang sein wie ein int'Ansatz) wird einige Probleme darstellen.

Mit dem C99 <stdint.h> und <inttypes.h> Header, Sie können feste Ganzzahlen mit fester Größe codieren-wenn Sie Maschinen mit 36-Bit- oder 60-Bit-Ganzzahlen ignorieren (was zumindest quasi legitimiert ist). Die meisten Code werden jedoch nicht mit diesen Typen geschrieben, und es gibt typischerweise tief sitzende und weitgehend versteckte (aber grundsätzlich fehlerhafte) Annahmen in dem Code, der verärgert ist, wenn das Modell von den vorhandenen Variationen abweist.

Beachten Sie das Ultra-konservative LLP64-Modell von Microsoft für 64-Bit-Fenster. Das wurde ausgewählt, weil zu viel alter Code brechen würde, wenn das 32-Bit-Modell geändert würde. Der Code, der auf ILP64- oder LP64 -Architekturen portiert worden war, war jedoch aufgrund der Unterschiede nicht sofort auf LLP64 tragbar. Verschwörungstheoretiker würden wahrscheinlich sagen, dass es absichtlich ausgewählt wurde, es zu erschweren, dass Code für 64-Bit-Unix auf 64-Bit-Fenster portiert wird. In der Praxis bezweifle ich, ob das mehr als ein glücklicher (für Microsoft) Nebeneffekt war; Der 32-Bit-Windows-Code musste viel überarbeitet werden, um das LP64-Modell ebenfalls zu verwenden.

Es gibt eine Code-Idiom, die brechen würde, wenn INTs 64 Bits wären, und ich sehe es oft genug, dass ich denke, dass es als vernünftig bezeichnet werden könnte:

  • Überprüfen Sie, ob ein Wert negativ ist, indem Sie testen, ob ((val & 0x80000000) != 0)

Dies wird häufig bei Überprüfungsfehlercodes gefunden. Viele Fehlercode -Standards (wie die Fenster des Fensters HRESULT) verwendet Bit 31, um einen Fehler darzustellen. Und Code prüft manchmal auf diesen Fehler, indem Sie entweder Bit 31 oder manchmal durch Überprüfen, ob der Fehler eine negative Zahl ist.

Microsofts Makros zum Testen von HRESULT verwenden beide Methoden - und ich bin sicher, dass es eine Menge Code gibt, die ohne die SDK -Makros ähnlich sind. Wenn MS auf ILP64 umgezogen wäre, wäre dies ein Bereich, der Portierungskopfschmerzen verursachte, die mit dem LLP64 -Modell (oder dem LP64 -Modell) vollständig vermieden werden.

Hinweis: Wenn Sie nicht mit Begriffen wie "ILP64" vertraut sind, sehen Sie sich das Mini-Gllossar am Ende der Antwort an.

Ich bin mir ziemlich sicher, dass es viele Code (nicht unbedingt Windows-orientiert) gibt, die es mit einfachem Alten verwenden, um Fehlercodes zu halten, vorausgesetzt, diese INT sind 32 Bit. Und ich wette, es gibt viel Code mit diesem Fehlerstatusschema, das auch beide Arten von Schecks verwendet (< 0 und Bit 31 wird festgelegt) und das würde brechen, wenn sie auf eine ILP64 -Plattform verschoben werden. Diese Überprüfungen könnten so in beiden Fällen ordnungsgemäß funktionieren, wenn die Fehlercodes sorgfältig konstruiert würden, sodass eine Anzeichenverdienerin stattfand. Wiederum haben viele solcher Systeme die Fehlerwerte konstruieren .

Wie auch immer, ich denke nicht, dass dies ein unlösbares Problem ist, aber ich denke, es ist eine ziemlich häufige Codierungspraxis, die dazu führen würde, dass eine Menge Code die Behebung erfordert, wenn sie auf eine ILP64 -Plattform verschoben werden.

Beachten Sie, dass ich auch nicht denke, dass dies einer der wichtigsten Gründe für Microsoft war, das LLP64-Modell zu wählen (ich denke in MSDN erwähnt und Auf Raymond Chens Blog).


Mini-Gllossar Für die 64-Bit-Plattform-Programmiermodellterminologie:

  • ILP64: int, long, Zeiger sind 64 Bit
  • LP64: long und Zeiger sind 64 Bits, int Wird 32-Bit (verwendet von vielen (meisten?) Unix-Plattformen)
  • LLP64: long long und Zeiger sind 64 Bits, int und long Bleiben Sie 32 Bit (verwendet auf Win64)

Weitere Informationen zu 64-Bit-Programmiermodellen finden Sie unter "64-Bit-Programmiermodelle: Warum LP64?"

Ich persönlich schreibe zwar keinen solchen Code, aber ich wette, dass er an mehr als einem Ort da draußen ist ... und natürlich wird es brechen, wenn Sie die Größe von ändern int.

int i, x = getInput();
for (i = 0; i < 32; i++)
{
    if (x & (1 << i))
    {
        //Do something
    }
}

Nun, es ist nicht so, dass diese Geschichte alles neu ist. Mit "meisten Computern" nehme ich an, dass Sie Desktop -Computer meinen. Es gab bereits einen Übergang von 16-Bit zu 32-Bit int. Gibt es überhaupt etwas, was besagt, dass diesmal der gleiche Fortschritt nicht passieren wird?

Nicht besonders. Int ist 64 Bit bei einigen 64 -Bit -Architekturen (nicht x64).

Der Standard garantiert nicht, dass Sie 32 -Bit -Ganzzahlen erhalten, nur dass (u) int32_t einen halten kann.

Wenn Sie nun auf die gleiche Größe wie pTRDIFF_T sind, können Sie möglicherweise unterbrochen werden.

Denken Sie daran, C garantiert nicht, dass die Maschine sogar eine binäre Maschine ist.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top