Konwersja wskaźnika na liczbę całkowitą
Próbuję dostosować istniejący kod do 64-bitowej maszyny. Głównym problemem jest to, że w jednej funkcji poprzedni koder używa argumentu void*, który jest konwertowany na odpowiedni typ w samej funkcji. Krótki przykład:
void function(MESSAGE_ID id, void* param)
{
if(id == FOO) {
int real_param = (int)param;
// ...
}
}
Oczywiście na 64-bitowej maszynie dostaję błąd:
error: cast from 'void*' to 'int' loses precision
Chciałbym to poprawić tak, aby nadal działało na maszynie 32-bitowej i tak czysto, jak to tylko możliwe. Jakiś pomysł ?
10 answers
Użyj intptr_t
i uintptr_t
.
Aby upewnić się, że jest zdefiniowany w sposób przenośny, możesz użyć kodu w następujący sposób:
#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
Po prostu umieść to w niektórych .plik h i dołącz tam, gdzie go potrzebujesz.
Alternatywnie możesz pobrać wersję pliku stdint.h
firmy Microsoft z tutaj lub użyć przenośnego z tutaj .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-28 08:19:21
Powiedziałbym, że jest to nowoczesny sposób C++.
#include <cstdint>
void *p;
auto i = reinterpret_cast<std::uintptr_t>(p);
EDIT :
Poprawny typ do liczby całkowitej
Więc właściwym sposobem przechowywania wskaźnika jako liczby całkowitej jest użycie typów uintptr_t
lub intptr_t
. (Zobacz także w cppreference integeger types for C99 ).
<stdint.h>
dla C99 oraz w przestrzeni nazw std
dla C++11 w <cstdint>
(Zobacz typy całkowite dla C++).
C++11 (i nowsze) Wersja
#include <cstdint>
std::uintptr_t i;
Wersja C++03
extern "C" {
#include <stdint.h>
}
uintptr_t i;
Wersja C99
#include <stdint.h>
uintptr_t i;
Prawidłowy operator odlewu
W C jest tylko jeden cast i używanie cast w C++ jest źle widziane(więc nie używaj go w C++). W C++ istnieją różne formy. reinterpret_cast
jest prawidłową obsadą dla tego nawrócenia (Zobacz także tutaj ).
Wersja C++11
auto i = reinterpret_cast<std::uintptr_t>(p);
Wersja C++03
uintptr_t i = reinterpret_cast<uintptr_t>(p);
C Wersja
uintptr_t i = (uintptr_t)p; // C Version
Podobne Pytania
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:30
'size_t ' i' ptrdiff_t ' są wymagane, aby pasowały do Twojej architektury (cokolwiek to jest). Dlatego myślę, że zamiast używać 'int', powinieneś być w stanie użyć 'size_t', który w systemie 64-bitowym powinien być typem 64-bitowym.
Ta dyskusja unsigned int vs size_t jest nieco bardziej szczegółowa.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:22
Użyj uintptr_t
jako typu integer.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-28 08:19:48
Kilka odpowiedzi wskazywało na uintptr_t
i #include <stdint.h>
jako "rozwiązanie". To jest, sugeruję, część odpowiedzi, ale nie cała odpowiedź. Musisz również spojrzeć na to, gdzie funkcja jest wywoływana z ID wiadomości FOO.
Rozważ ten kod i kompilację:
$ 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
$
Zauważysz, że istnieje problem w miejscu wywołania (w main()
) - konwersja liczby całkowitej na wskaźnik bez obsady. Będziesz musiał przeanalizować swój function()
we wszystkich jego zastosowaniach, aby zobaczyć, jak wartości są przekazywane do niego. Kod w moim function()
zadziałałby, gdyby wywołania były napisane:
unsigned long i = 0x2341;
function(1, &i);
Ponieważ twoje są prawdopodobnie napisane inaczej, musisz przejrzeć punkty, w których funkcja jest wywoływana, aby upewnić się, że sensowne jest użycie wartości, jak pokazano. Nie zapominaj, że możesz znaleźć ukryty błąd.
Ponadto, jeśli zamierzasz sformatować wartość parametru void *
(jako przekonwertowanego), przyjrzyj się uważnie nagłówkowi <inttypes.h>
(zamiast stdint.h
- inttypes.h
świadczy usługi z stdint.h
, co jest niezwykłe, ale standard C99 mówi [t] he header <inttypes.h>
zawiera nagłówek <stdint.h>
i rozszerza go o
dodatkowe udogodnienia dostarczane przez hostowane implementacje ) i używać makr PRIxxx w ciągach formatujących.
Ponadto Moje komentarze są ściśle stosowane do C, a nie C++, ale twój kod jest w podzbiorze C++, który jest przenośny między C i C++. Szanse są słuszne, że moje komentarze mają zastosowanie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-31 00:08:37
Myślę ,że" znaczenie " void* w tym przypadku jest ogólnym uchwytem. Nie jest wskaźnikiem do wartości, jest samą wartością. (Tak się składa, że void* jest używany przez programistów C i C++.)
Jeśli posiada wartość całkowitą, to lepiej, żeby była w zakresie liczby całkowitej!
Tutaj jest łatwe renderowanie do liczby całkowitej:
int x = (char*)p - (char*)0;
Powinno dać tylko Ostrzeżenie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-10 06:47:52
#include <stdint.h>
- Użyj standardowego typu
uintptr_t
zdefiniowanego w dołączonym standardowym pliku nagłówkowym.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-04 21:19:19
Najlepszą rzeczą do zrobienia jest uniknięcie konwersji z typu wskaźnika do typu nie-wskaźnika. Nie jest to jednak możliwe w Twoim przypadku.
Jak wszyscy mówili, uintptr_t jest tym, czego powinieneś używać.
Ten link ma dobre informacje o konwersji na kod 64-bitowy.
Jest również dobra dyskusja na ten temat na comp.choroby weneryczne.c
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-30 14:05:07
Natknąłem się na to pytanie studiując kod źródłowy SQLite.
W sqliteInt.h , jest paragraf kodu zdefiniowany makro konwersja między liczbą całkowitą a wskaźnikiem. Autor wygłosił bardzo dobre stwierdzenie, najpierw wskazując, że powinien to być problem zależny od kompilatora, a następnie zaimplementował rozwiązanie, aby uwzględnić większość popularnych kompilatorów.
#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
A oto cytat komentarza po więcej szczegółów:
/*
** 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.
*/
Kredyt idzie do Komisji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-25 17:11:55
Ponieważ uintptr_t
jest nie ma gwarancji, że będzie tam w C++ / C++11, jeśli jest to konwersja jednokierunkowa, możesz rozważyć uintmax_t
, zawsze zdefiniowana w <cstdint>
.
auto real_param = reinterpret_cast<uintmax_t>(param);
Aby grać bezpiecznie, można w dowolnym miejscu w kodzie dodać twierdzenie:
static_assert(sizeof (uintmax_t) >= sizeof (void *) ,
"No suitable integer type for conversion from pointer type");
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-19 16:40:30