Frage

Ich versuche, einen vorhandenen Code auf eine 64-Bit-Maschine anzupassen. Das Hauptproblem besteht darin, daß in einer Funktion, die vorherigen Coder ein void * Argument verwendet, die in geeignete Art in der Funktion selbst überführt wird. Ein kurzes Beispiel:

void function(MESSAGE_ID id, void* param)
{
    if(id == FOO) {
        int real_param = (int)param;
        // ...
    }
}

Natürlich auf einer 64-Bit-Maschine, erhalte ich die Fehlermeldung:

error: cast from 'void*' to 'int' loses precision

Ich möchte, dies korrigieren, so dass es nach wie vor auf einer 32-Bit-Maschine arbeitet und so sauber wie möglich. Jede Idee?

War es hilfreich?

Lösung

Mit intptr_t und uintptr_t.

Um sicherzustellen, dass es in einer tragbaren Weise definiert ist, können Sie folgenden Code verwenden können:

#if defined(__BORLANDC__)
    typedef unsigned char uint8_t;
    typedef __int64 int64_t;
    typedef unsigned long uintptr_t;
#elif defined(_MSC_VER)
    typedef unsigned char uint8_t;
    typedef __int64 int64_t;
#else
    #include <stdint.h>
#endif

Einfach setzen, dass in einigen .h-Datei und sind überall dort, wo Sie es brauchen.

Alternativ können Sie Microsofts Version der stdint.h Datei aus http: // www.azillionmonkeys.com/qed/pstdint.h‘rel = "noreferrer"> hier .

Andere Tipps

Ich würde sagen, das ist die moderne C ++ Art und Weise.

#include <cstdint>
void *p;
auto i = reinterpret_cast<std::uintptr_t>(p);

Bearbeiten :

Der richtige Typ der die Integer

so die richtige Weise einen Zeiger zu speichern, wie eine ganze Zahl ist, die uintptr_t oder intptr_t Typen zu verwenden. (Siehe auch in cppreference Integer-Typ für C99 ).

Diese Typen sind in <stdint.h> für C99 und im Namensraum std definiert für C ++ 11 in <cstdint> (siehe integer-Typen für C ++ ).

C ++ 11 (und an) Version

#include <cstdint>
std::uintptr_t i;

C ++ 03 Version

extern "C" {
#include <stdint.h>
}

uintptr_t i;

C99 Version

#include <stdint.h>
uintptr_t i;

Der richtige Casting-Operator

In C gibt es nur eine gegossene und mit dem C-Cast in C ++ verpönte auf (so verwenden Sie es nicht in C ++). In C ++ gibt es verschiedene Würfe. reinterpret_cast ist die richtige Besetzung für diese Umwandlung (Siehe auch hier ).

C ++ 11 Version

auto i = reinterpret_cast<std::uintptr_t>(p);

C ++ 03 Version

uintptr_t i = reinterpret_cast<uintptr_t>(p);

C Version

uintptr_t i = (uintptr_t)p; // C Version

Verwandte Fragen

‚size_t‘ und ‚ptrdiff_t‘ werden benötigt, um Ihre Architektur entsprechen (was auch immer es ist). Deshalb glaube ich, eher als ‚int‘ verwenden, sollten Sie in der Lage sein ‚size_t‘ zu verwenden, die auf einem 64-Bit-System sollen ein 64-Bit-Typ sein.

Diese Diskussion unsigned int vs size_t geht in ein wenig mehr Details.

Verwenden uintptr_t als Integer-Typ.

Einige Antworten wurden bei uintptr_t und #include <stdint.h> als ‚die‘ Lösung hingewiesen. Das heißt, schlage ich vor, einen Teil der Antwort, aber nicht die ganze Antwort. Sie müssen auch sehen, wo die Funktion mit der Nachrichten-ID von FOO aufgerufen wird.

Betrachten Sie diesen Code und Zusammenstellung:

$ cat kk.c
#include <stdio.h>
static void function(int n, void *p)
{
    unsigned long z = *(unsigned long *)p;
    printf("%d - %lu\n", n, z);
}

int main(void)
{
    function(1, 2);
    return(0);
}
$ rmk kk
        gcc -m64 -g -O -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith \
            -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes \
            -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE kk.c -o kk 
kk.c: In function 'main':
kk.c:10: warning: passing argument 2 of 'func' makes pointer from integer without a cast
$

Sie werden feststellen, dass es ein Problem in der anrufenden Stelle ist (in main()) - eine ganze Zahl auf einen Zeiger ohne Guss umgewandelt wird. Sie gehen zu müssen, Ihre function() in all seinen Nutzungen zu analysieren, um zu sehen, wie die Werte an sie übergeben werden. Der Code in meinem function() funktionieren würde, wenn die Anrufe geschrieben wurden:

unsigned long i = 0x2341;
function(1, &i);

Da Ihr wahrscheinlich anders geschrieben werden, müssen Sie die Punkte überprüfen, wenn die Funktion aufgerufen wird, um sicherzustellen, dass es Sinn macht, den Wert zu verwenden, wie gezeigt. Vergessen Sie nicht, können Sie einen latenten Fehler werden zu finden.

Auch wenn Sie den Wert des void * Parameter (wie konvertierte) zu formatieren, gehen, schauen Sie genau auf die <inttypes.h> Header (statt stdint.h - inttypes.h bietet die Dienste von stdint.h, was ungewöhnlich ist, aber der C99-Standard sagt < em> [d] ie <inttypes.h> Header enthält den Header <stdint.h> und erweitert sie mit zusätzliche Einrichtungen von gehosteten Implementierungen zur Verfügung gestellt ) und die PRIxxx Makros in Ihren Format-Strings verwendet werden.

Auch sind meine Kommentare zu C streng anwendbar und nicht C ++, aber der Code ist in der Teilmenge von C ++, die zwischen C und C ++ tragbar ist. Die Chancen sind fair zu gut, dass meine Bemerkungen gelten.

  1. #include <stdint.h>
  2. Verwenden uintptr_t Standardtyp in der mitgelieferten Standard-Header-Datei definiert.

Ich denke, die „Bedeutung“ von void * in diesem Fall ist ein allgemeiner Griff. Es ist nicht ein Zeiger auf einen Wert, ist es der Wert selbst. (Dies geschieht nur zu sein, wie void * verwendet wird von C und C ++ Programmierern.)

Wenn es einen ganzzahligen Wert hält, ist es besser im Integer-Bereich hatte!

Hier ist einfach Rendering integer:

int x = (char*)p - (char*)0;

Es sollte nur eine Warnung aus.

ich auf diese Frage kam, während den Quellcode SQLite .

In der sqliteInt.h gibt ist ein Absatz des Code ein Makro Konvertieren zwischen Integer- und Zeiger definiert ist. Der Autor hat eine sehr gute Aussage unter Hinweis darauf, zunächst sollte es ein Compiler abhängig Problem sein und implementiert dann die Lösung für die meisten populären Compiler da draußen zu berücksichtigen.

#if defined(__PTRDIFF_TYPE__)  /* This case should work for GCC */
# define SQLITE_INT_TO_PTR(X)  ((void*)(__PTRDIFF_TYPE__)(X))
# define SQLITE_PTR_TO_INT(X)  ((int)(__PTRDIFF_TYPE__)(X))
#elif !defined(__GNUC__)       /* Works for compilers other than LLVM */
# define SQLITE_INT_TO_PTR(X)  ((void*)&((char*)0)[X])
# define SQLITE_PTR_TO_INT(X)  ((int)(((char*)X)-(char*)0))
#elif defined(HAVE_STDINT_H)   /* Use this case if we have ANSI headers */
# define SQLITE_INT_TO_PTR(X)  ((void*)(intptr_t)(X))
# define SQLITE_PTR_TO_INT(X)  ((int)(intptr_t)(X))
#else                          /* Generates a warning - but it always works     */
# define SQLITE_INT_TO_PTR(X)  ((void*)(X))
# define SQLITE_PTR_TO_INT(X)  ((int)(X))
#endif

Und hier ist ein Zitat des Kommentars für weitere Informationen:

/*
** The following macros are used to cast pointers to integers and
** integers to pointers.  The way you do this varies from one compiler
** to the next, so we have developed the following set of #if statements
** to generate appropriate macros for a wide range of compilers.
**
** The correct "ANSI" way to do this is to use the intptr_t type.
** Unfortunately, that typedef is not available on all compilers, or
** if it is available, it requires an #include of specific headers
** that vary from one machine to the next.
**
** Ticket #3860:  The llvm-gcc-4.2 compiler from Apple chokes on
** the ((void*)&((char*)0)[X]) construct.  But MSVC chokes on ((void*)(X)).
** So we have to define the macros in different ways depending on the
** compiler.
*/

Kredit geht an die Committer.

Das Beste, was zu tun ist, vom Zeigertyp nicht-Zeigertypen zu vermeiden, zu konvertieren. Dies ist jedoch eindeutig nicht möglich, in Ihrem Fall.

Wie jeder gesagt, die uintptr_t was Sie verwenden sollen.

Das Link hat gute Infos über die Umstellung auf 64-Bit-Code.

Es gibt auch eine gute Diskussion dieser auf comp. std.c

Da uintptr_t nicht in C, dort sein garantierte ++ / C ++ 11 wenn diese eine Umwandlung eines Weges ist, Sie können uintmax_t betrachten, immer definiert in <cstdint> .

auto real_param = reinterpret_cast<uintmax_t>(param);

Um sicher zu gehen, konnte man überall in dem Code eine Behauptung hinzuzufügen:

static_assert(sizeof (uintmax_t) >= sizeof (void *) ,
              "No suitable integer type for conversion from pointer type");
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top