Ich habe gerade mit dem WinAPI angefangen. In der MSDN wird die folgende Erläuterung für den Datentyp WORD bereitgestellt.
WORT
Eine 16-Bit-Ganzzahl ohne Vorzeichen. Der Bereich ist 0 bis 65535 dezimal.
Dieser Typ wird in WinDef.h wie folgt deklariert:
typedef unsigned short WORD;
Einfach genug, und es passt zu den anderen Ressourcen, die ich zum Lernen verwendet habe, aber wie kann es definitiv gesagt werden, dass es 16 Bits sind? Die C-Dateitypen Seite in Wikipedia gibt
ankurz / kurz int / signiert kurz / signiert kurz int Kurze vorzeichenbehaftete Ganzzahl Art. Kann mindestens den Bereich [-32767, +32767] enthalten; so, es ist mindestens 16 Bits groß.
Die Größe eines short
könnte also nach dem C-Standard sehr gut 32 Bit betragen. Aber wer entscheidet, welche Bitgrößen sowieso verwendet werden? Ich fand eine praktische Erklärung hier. Insbesondere die Zeile:
... es hängt von beiden Prozessoren ab (genauer ISA, Anweisung) Architektur, z. B. x86 und x86-64) und Compiler einschließlich Programmiermodell.
Also ist es die ISA, die einen Sinn ergibt, nehme ich an. Hier bin ich verloren. Werfen wir einen Blick auf die Windows-Seite auf Wikipedia, die ich in der Seitenleiste sehe:
Plattformen ARM, IA-32, Itanium, x86-64, DEC-Alpha, MIPS, PowerPC
Ich weiß nicht wirklich, was das ist, aber ich denke, das sind Prozessoren, von denen jeder eine ISA haben würde. Vielleicht unterstützt Windows diese Plattformen, weil sie garantiert 16 Bits pro unsigned short
verwenden? Das hört sich nicht ganz richtig an, aber ich weiß nicht genug über dieses Zeug, um weiter zu recherchieren.
Zurück zu meiner Frage: Wie kann es sein, dass die Windows-API typedef unsigned short WORD;
und dann WORD
eine vorzeichenlose 16-Bit-Ganzzahl ist, wenn der C-Standard selbst nicht garantiert, dass ein short
immer 16 Bits ist?
Einfach gesagt, ein WORD
ist immer 16 Bits.
Ein WORD
ist immer 16 Bits, aber ein unsigned short
ist nicht, ein WORD
ist nicht immer ein unsigned short
.
Für jede Plattform, die vom Windows SDK unterstützt wird, enthält die Windows-Headerdatei #ifdef
style-Makros, die den Compiler und seine Plattform erkennen und die vom Windows SDK definierten Typen ( WORD
, DWORD
usw.) zuordnen können die entsprechend großen Plattformtypen.
Dies ist der Grund, warum das Windows SDK tatsächlich intern definierte Typen wie WORD
anstelle von Sprachtypen verwendet, damit sie sicherstellen können, dass ihre Definitionen immer korrekt sind.
Das Windows SDK, das mit Microsoft Toolchains ausgeliefert wird, ist möglicherweise faul, da Microsoft C ++ - Toolchains immer unsignierte 16-Bit-Kurzschlüsse verwenden.
Ich würde nicht erwarten, dass die windows.h, die mit Visual Studio C ++ ausgeliefert wird, korrekt funktioniert, wenn sie in GCC, clang usw. fallen, da so viele Details, einschließlich des Mechanismus zum Importieren von DLLs mit .iib-Dateien, die das Platform SDK verteilen eine Microsoft-spezifische Implementierung.
Eine andere Interpretation ist das:
Microsoft sagt ein WORD
ist 16 Bits. Wenn "jemand" eine Windows-API aufrufen möchte, muss ein 16-Bit-Wert übergeben werden, wobei die API das Feld als WORD definiert.
Microsoft möglicherweise auch sagt, um ein gültiges Windows-Programm zu erstellen, mit den Windows-Header-Dateien in ihrem Windows SDK vorhanden, muss der Benutzer einen Compiler wählen, der eine 16bit short
hat.
Die C ++ - Spezifikation sagt nicht, dass Compiler short
s als 16 Bits implementieren müssen - Microsoft sagt, dass der Compiler, den Sie zum Erstellen von Windows-Executables auswählen, muss.
Ursprünglich wurde angenommen, dass der gesamte Code, der unter Windows ausgeführt werden soll, mit dem eigenen Compiler von Microsoft kompiliert werden würde - oder mit einem vollständig kompatiblen Compiler. Und so hat es funktioniert. Borland C: Matched Microsoft C. Zortechs C: Matched Microsoft C. gcc: nicht so sehr, also hast du es nicht einmal versucht (ganz zu schweigen davon, dass es keine Laufzeiten gab, etc.).
Im Laufe der Zeit wurde dieses Konzept kodifiziert und auf andere Betriebssysteme erweitert (oder vielleicht haben die anderen Betriebssysteme es zuerst bekommen) und jetzt ist es bekannt als ein ABI - Binäre Anwendungsschnittstelle - für eine Plattform und alle Compiler für diese Plattform werden (in der Praxis vorausgesetzt) als ABI-konform angenommen. Und das bedeutet unter anderem, die Erwartungen an die Größen der integralen Typen anzupassen.
Eine interessante verwandte Frage, die Sie nicht gestellt haben, ist: Warum werden 16-Bit ein Wort genannt? Warum ist 32-Bit ein dword (Doppelwort) auf unseren 32- und jetzt 64-Bit-Architekturen, wo die native Maschine "Wort" -Größe 32- oder 64- ist, nicht 16? Weil: 80286.
In den Windows-Headern gibt es eine Menge #define, die basierend auf der Plattform sicherstellen können, dass ein WORD 16 Bit, ein DWORD 32 usw. ist. In einigen Fällen weiß ich, dass sie ein richtiges SDK für jede Plattform verteilen . Auf jeden Fall nichts magisches, nur eine Mischung aus richtigen #defines und headern.
Die Terminologie BYTE=8bits
, WORD=16bits
und DWORD=32bits
(Doppelwort) stammt aus Intels Instruktions-Mnemonics und Dokumentation für 8086. Es ist nur eine Terminologie und impliziert zu diesem Zeitpunkt nichts über die Größe des" Maschinenworts " auf der tatsächlichen Maschine, auf der der Code ausgeführt wird.
Meine Vermutung:
Diese C-Typnamen wurden wahrscheinlich ursprünglich aus demselben Grund eingeführt wie C99 standardisiert uint8_t
, uint16_t
und uint32_t
. Die Idee war wahrscheinlich, C-Implementierungen mit einem inkompatiblen ABI (zB 16bit int
oder 32bit short
) weiterhin Code zu kompilieren, der die WinAPI verwendet, weil die ABI DWORD
anstatt long
oder int
verwendet struct
s und Funktion args / return values.
Wahrscheinlich ist Windows so weit entwickelt, dass genug Code auf verschiedene Arten auf die genaue Definition von WORD und DWORD angewiesen ist, die MS zu standardisieren Sie die genaue typedef
s . Dies unterscheidet sich von der C99 uint16_t
Idee, bei der Sie nicht davon ausgehen können, dass es unsigned short
ist.
Als @supercat weist darauf hin , das kann für Aliasing-Regeln von Bedeutung sein. z.B. Wenn Sie ein Array von unsigned long[]
bis DWORD*
ändern, ist garantiert, dass es wie erwartet funktioniert. Wenn Sie jedoch ein Array von unsigned int[]
durch DWORD*
ändern, könnte der Compiler davon ausgehen, dass Array-Werte, die er bereits in Registern hatte, nicht betroffen waren. Dies gilt auch für printf
Formatzeichenfolgen. (C99's <stdint.h>
Lösung dazu ist Präprozessormakros wie PRIu32
.)
Oder vielleicht bestand die Idee nur darin, Namen zu verwenden, die mit dem asm übereinstimmen, um sicherzustellen, dass niemand über die Breite der Typen verwirrt ist. In den frühen Tagen von Windows war das Schreiben von Programmen in Asm direkt statt C populär. WORD / DWORD macht die Dokumentation für Personen, die in asm schreiben, klarer.
Oder vielleicht bestand die Idee nur darin, einen Typ mit fester Breite für portablen Code bereitzustellen . z.B. #ifdef SUNOS
: Definieren Sie einen passenden Typ für diese Plattform. Das ist alles, was zu diesem Zeitpunkt gut ist, wie Sie bemerkt haben:
Wie kann es sein, dass die Windows-API typedef unsigned short WORD eingeben kann? und dann sagen WORD ist eine 16-Bit-Ganzzahl ohne Vorzeichen, wenn der C-Standard selbst nicht garantiert, dass ein Kurzschluss immer 16 Bits ist?
Sie haben Recht, wenn Sie das genaue typedef
s dokumentieren, ist es unmöglich, die WinAPI-Header in einem System mit einem anderen ABI korrekt zu implementieren (z. B. mit long
ist 64bit oder short
ist 32bit). Dies ist einer der Gründe, warum der x86-64 Windows ABI long
zu einem 32bit Typ macht. Das x86-64-System V ABI (Linux, OS X usw.) macht long
zu einem 64-Bit-Typ.
Jede Plattform benötigt jedoch einen Standard-ABI, . struct
layout und sogar die Interpretation von Funktionsargumenten erfordert, dass der gesamte Code der Größe der verwendeten Typen entspricht. Code aus verschiedenen Versionen desselben C-Compilers kann zusammenarbeiten und sogar andere Compiler, die demselben ABI folgen. (C ++ - ABIs sind jedoch nicht stabil genug, um zu standardisieren. Zum Beispiel hat g++
niemals einen ABI standardisiert, und neue Versionen brechen die ABI-Kompatibilität.)
Denken Sie daran, dass der C-Standard Ihnen nur sagt, was Sie bei jeder konformen C-Implementierung erwarten können. Der C-Standard besagt auch, dass vorzeichenbehaftete Ganzzahlen Zeichen / Betrag, Einerkomplement oder Zweierkomplement sein können. Jede spezifische Plattform verwendet jedoch jede Darstellung der Hardware.
Plattformen können alles standardisieren, was der Basis-C-Standard nicht definiert oder implementierungsdefiniert lässt. z.B. x86 C-Implementierungen ermöglichen das Erstellen von nicht ausgerichteten Zeigern und sogar deren Dereferenzierung. Dies geschieht sehr häufig mit __m128i
vector types.
Die gewählten Namen binden die WinAPI an ihr x86-Erbe und sind leider verwirrend für alle, die sich nicht mit x86 asm oder zumindest mit dem 16-Bit-DOS-Erbe von Windows auskennen.
Die 8086-Befehls-Mnemotechniken, die w
für Word und d
für dword enthalten, wurden häufig als Setup für % co_de verwendet % signierte Division .
idiv
: Zeichen verlängern AL (Byte) in AX (Wort) cbw
: zeichen erweitern AX (Wort) in DX: AX (dword) , dh kopieren das Vorzeichen-Bit von cwd
in jedes Bit von ax
. Diese Insnts existieren immer noch und machen genau dasselbe im 32-Bit- und 64-Bit-Modus.
Derzeit gibt es keine Plattformen, die Windows API unterstützen, aber unsigned short
als nicht 16-bit.
Wenn jemand jemals eine solche Plattform erstellt hat, enthalten die Windows-API-Header für diese Plattform nicht die Zeile typedef unsigned short WORD;
.
Sie können sich MSDN-Seiten als typisches Verhalten von MSVC ++ auf x86 / x64-Plattformen vorstellen.
Das Legacy für Typen wie WORD ist älter als Windows, zurück zu den Tagen von MSDOS nach den Typen, die von MASM definiert wurden (später wurde der Name in ML geändert). Von der Windows-API nicht übernommen sind MASMs signierte Typen wie SBYTE, SWORD, SDWORD, SQWORD.
QWORD / SQWORD in MASM wurde wahrscheinlich nicht definiert, bis MASM / ML 80386 unterstützt.
Eine aktuelle Referenz:
Windows hat Typen wie HANDLE, WCHAR, TCHAR, ... hinzugefügt.
Bei Windows / Microsoft-Compilern ist size_t eine vorzeichenlose Ganzzahl mit der gleichen Größe wie ein Poitner, 32 Bit im 32-Bit-Modus, 64 Bit im 64-Bit-Modus.
Die DB- und DW-Datenanweisungen in MASM gehen auf die Tage von Intels 8080-Assembler zurück.