Ich versuche, einen vorhandenen Code an eine 64-Bit-Maschine anzupassen. Das Hauptproblem besteht darin, dass der vorherige Codierer in einer Funktion ein void * -Argument verwendet, das in der Funktion selbst in einen geeigneten Typ konvertiert wird. Ein kurzes Beispiel:
void function(MESSAGE_ID id, void* param)
{
if(id == FOO) {
int real_param = (int)param;
// ...
}
}
Auf einem 64-Bit-Computer erhalte ich natürlich die folgende Fehlermeldung:
error: cast from 'void*' to 'int' loses precision
Ich möchte dies korrigieren, damit es auf einem 32-Bit-Computer immer noch und so sauber wie möglich funktioniert. Irgendeine Idee ?
size_t
nicht funktioniert, ist der segmentierte i386-Speicher. Obwohl eine 32-Bit-Maschine,sizeof
kehrt2
für zurücksize_t
. Die Antwort von Alex unten scheint korrekt zu sein. Alex 'Antwort unduintptr_t
funktioniert fast überall und ist jetzt Standard. Es bietet eine C ++ 11-Behandlung und sogar die C ++ 03-Header-Schutzvorrichtungen.Antworten:
Verwenden Sie
intptr_t
unduintptr_t
.Um sicherzustellen, dass es portabel definiert ist, können Sie folgenden Code verwenden:
Legen Sie das einfach in eine .h-Datei und fügen Sie es dort ein, wo Sie es benötigen.
Alternativ können Sie die Microsoft-Version der
stdint.h
Datei von hier herunterladen oder eine tragbare Version von hier verwenden .quelle
<cstdint>
, zu der entsprechenden zu wechseln oder diese herunterzuladen,cstdint
wenn Sie eine herunterladenstdint.h
.cstdint
Teil des C ++ - Standards, ebenso wie alle dort definierten Typnamen. Es ist in der Tat für die angegebenen Tags geeignet. ... Ich bin nicht damit einverstanden, die Typen manuell zu definieren, aber es kann erforderlich sein, wenn Sie mit Compilern arbeiten, die dies nicht tun.Ich würde sagen, dies ist der moderne C ++ - Weg.
BEARBEITEN :
Der richtige Typ für die Ganzzahl
Der richtige Weg, einen Zeiger als Ganzzahl zu speichern, besteht darin, die Typen
uintptr_t
oder zuintptr_t
verwenden. (Siehe auch in cppreference Integer-Typen für C99 ).Diese Typen sind in
<stdint.h>
C99 und im Namespacestd
für C ++ 11 in definiert<cstdint>
(siehe Integer-Typen für C ++ ).C ++ 11 (und höher) Version
C ++ 03 Version
C99 Version
Der richtige Casting-Operator
In C gibt es nur eine Besetzung, und die Verwendung der C-Besetzung in C ++ ist verpönt (verwenden Sie sie also nicht in C ++). In C ++ gibt es verschiedene Casts.
reinterpret_cast
ist die richtige Besetzung für diese Konvertierung (siehe auch hier ).C ++ 11 Version
C ++ 03 Version
C-Version
Verwandte Fragen
quelle
uintptr_t
statt zu verwendensize_t
, warum ist es dann erforderlichreinterpret_cast
? Es scheint einfach zustatic_cast
sein, da der Standard speziell die kompatiblen Datentypen bereitstellt ...static_cast
der Typ möglicherweise konvertiert wird oder wenn es sich um einen Zeiger handelt, Zeigeranpassungen vornehmen können, wenn der Typ dies benötigt.reinterpret_cast
ändert wirklich nur den Typ des zugrunde liegenden Speichermusters (keine Mutationen). zu verdeutlichen:static_cast
verhält sich hier identisch.'size_t' und 'ptrdiff_t' sind erforderlich, um Ihrer Architektur zu entsprechen (was auch immer es ist). Daher denke ich, anstatt 'int' zu verwenden, sollten Sie in der Lage sein, 'size_t' zu verwenden, das auf einem 64-Bit-System ein 64-Bit-Typ sein sollte.
Diese Diskussion ohne Vorzeichen int vs size_t geht etwas detaillierter.
quelle
size_t
dass es das Ergebnis von jedem enthalten musssizeof()
. Dies macht es nicht unbedingt 64 Bit auf x64. siehe auchsize_t
kann den Wert eines Nichtmitgliedszeigers sicher speichern. Siehe en.cppreference.com/w/cpp/types/size_t .Verwenden Sie
uintptr_t
als Ganzzahltyp.quelle
Mehrere Antworten haben auf
uintptr_t
und hingewiesen#include <stdint.h>
als "die" Lösung . Das ist, wie ich vorschlage, ein Teil der Antwort, aber nicht die ganze Antwort. Sie müssen auch überprüfen, wo die Funktion mit der Nachrichten-ID von FOO aufgerufen wird.Betrachten Sie diesen Code und die Zusammenstellung:
Sie werden feststellen, dass am aufrufenden Ort (in
main()
) ein Problem vorliegt - das Konvertieren einer Ganzzahl in einen Zeiger ohne Umwandlung. Sie müssen Ihrefunction()
in all ihren Verwendungen analysieren, um zu sehen, wie Werte an sie übergeben werden. Der Code in meinemfunction()
würde funktionieren, wenn die Aufrufe geschrieben würden:Da Ihre wahrscheinlich anders geschrieben sind, müssen Sie die Punkte überprüfen, an denen die Funktion aufgerufen wird, um sicherzustellen, dass es sinnvoll ist, den angegebenen Wert zu verwenden. Vergessen Sie nicht, dass Sie möglicherweise einen latenten Fehler finden.
Wenn Sie den Wert des
void *
Parameters (wie konvertiert) formatieren möchten, schauen Sie sich den<inttypes.h>
Header genau an (anstelle vonstdint.h
-inttypes.h
bietet die Dienste vonstdint.h
, was ungewöhnlich ist, aber der C99-Standard besagt, dass der Header<inttypes.h>
den Header<stdint.h>
und enthält erweitert es um zusätzliche Funktionen, die von gehosteten Implementierungen bereitgestellt werden ) und verwendet die PRIxxx-Makros in Ihren Formatzeichenfolgen.Außerdem gelten meine Kommentare ausschließlich für C und nicht für C ++, aber Ihr Code befindet sich in der Teilmenge von C ++, die zwischen C und C ++ portierbar ist. Die Chancen stehen gut bis gut, dass meine Kommentare zutreffen.
quelle
#include <stdint.h>
uintptr_t
in der enthaltenen Standard-Header-Datei definierten Standardtyp.quelle
Ich bin auf diese Frage gestoßen, als ich den Quellcode von SQLite studiert habe .
In der Datei sqliteInt.h ist ein Absatz des Codes definiert, der eine Makrokonvertierung zwischen Ganzzahl und Zeiger definiert. Der Autor gab eine sehr gute Erklärung ab und wies zunächst darauf hin, dass es sich um ein compilerabhängiges Problem handeln sollte, und implementierte dann die Lösung, um die meisten gängigen Compiler zu berücksichtigen.
Und hier ist ein Zitat des Kommentars für weitere Details:
Der Kredit geht an die Committer.
quelle
Am besten vermeiden Sie die Konvertierung vom Zeigertyp in Nicht-Zeigertypen. Dies ist in Ihrem Fall jedoch eindeutig nicht möglich.
Wie alle sagten, sollten Sie uintptr_t verwenden.
Dieser Link enthält gute Informationen zur Konvertierung in 64-Bit-Code.
Es gibt auch eine gute Diskussion darüber auf comp.std.c
quelle
Ich denke, die "Bedeutung" von void * ist in diesem Fall ein generischer Griff. Es ist kein Zeiger auf einen Wert, es ist der Wert selbst. (Dies ist zufällig die Verwendung von void * durch C- und C ++ - Programmierer.)
Wenn es einen ganzzahligen Wert enthält, sollte es besser im ganzzahligen Bereich liegen!
Hier ist einfaches Rendern in Ganzzahlen:
Es sollte nur eine Warnung geben.
quelle
Da
uintptr_t
ist nicht in C , dort zu sein garantiert ++ / C ++ 11 , wenn dies eine Einbahn Umwandlung ist , kann man bedenktuintmax_t
, immer definiert in<cstdint>
.Um auf Nummer sicher zu gehen, könnte man irgendwo im Code eine Behauptung hinzufügen:
quelle