2012-02-29 17 views
21

Czy warto używać intptr_t jako pamięci ogólnego przeznaczenia (do przechowywania wskaźników i wartości całkowitych) zamiast void*? (Jak widać tutaj: http://www.crystalspace3d.org/docs/online/manual/Api1_005f0-64_002dBit-Portability-Changes.html)Używanie intptr_t zamiast void *?

za to, co już odczytać:

  • int ->void* ->int w obie strony nie gwarantuje posiadania oryginalnej wartości; Chyba int ->intptr_t ->int zrobi
  • wskaźnika arytmetyki zarówno void* i intptr_t wymagają odlewane, więc nikt nie dostaje przewagę tutaj
  • void* oznacza mniej wyraźne odlewy podczas zapisywania wskazówek, intptr_t oznacza mniej odlewane gdy wartości przechowywania całkowitą
  • intptr_t wymaga C99

Co jeszcze powinienem wziąć pod uwagę?

+0

Nie. (Jeśli tak, to po prostu dodaliby semantykę intptr_t do 'void *') –

+0

Wpis pyta "(aby trzymać wskaźniki i wartości całkowite)", ale wtedy tylko omawia 'int',' void * 'i' intptr_t'. Jako 'uintmax_t',' size_t', 'long long', itp. Są również typu integer, brzmi to tak, jakby pytanie dotyczyło tylko wskaźników obiektów, typów' intptr_t' i 'int'. – chux

Odpowiedz

25

Czy to dobry pomysł, aby użyć intptr_t jako magazyn ogólnego przeznaczenia (do przechowywania wskaźników i wartości całkowite) zamiast void*?

nr

intptr_t nie gwarantuje istnieć. Po pierwsze, jak zauważyłeś, została wprowadzona w C99. Po drugie, implementacje nie muszą mieć typu całkowitoliczbowego wystarczająco dużego, aby pomieścić wartości konwertowanych wskaźników bez utraty informacji.

przekształcania int do intptr_t iz powrotem nieprawdopodobne stracić informacji, ale nie ma gwarancji, że rzeczywista intptr_t jest szerszy niż int.

Jeśli chcesz przechowywać wartości wskaźników, przechowuj je w obiektach wskaźnikowych. Do tego służą obiekty wskaźnikowe.

Każdy wskaźnik do obiektu lub niekompletny typ można przekonwertować na void* iz powrotem, bez utraty informacji. Nie ma takiej gwarancji na wskaźniki dla funkcji - ale każdy wskaźnik typu funkcja może zostać przekonwertowany na dowolny inny wskaźnik na typ funkcji i z powrotem bez utraty informacji. (Odnoszę się do standardu C, myślę, że POSIX zapewnia dodatkowe gwarancje.)

Jeśli chcesz przechowywać wartość całkowitą lub wskaźnik w tym samym obiekcie, pierwszą rzeczą, którą powinieneś zrobić, jest ponowne przemyślenie twój projekt. Jeśli już to zrobiłeś i doszedłeś do wniosku, że naprawdę chcesz to zrobić, rozważ użycie unii (i uważnie śledząc, jaką wartość ostatnio przechowywałeś).

Istnieją interfejsy API używające argumentu void* do umożliwienia przekazywania dowolnych danych; patrz na przykład funkcja POSIX pthread_create(). Można to wykorzystać, rzucając wartość całkowitą na void*, ale bezpieczniej jest przekazać adres adres obiektu całkowitoliczbowego.

+2

Proszę rozwinąć "_nie prawdopodobne_, aby stracić informacje". 'intptr_t' robi w obie strony wskaźnik do porównywania _equally_ - jest to potencjalnie nie-ten sam bitowy wzór utraty informacji o twoim komentarzu. – chux

+2

@chux: Jak powiedziałem, nie ma gwarancji, że 'intptr_t' jest szerszy niż' int' (choć nie znam realizacji, gdzie nie jest). Jeśli, na przykład 'intptr_t' ma długość 32 bitów i' int' wynosi 64 bity, a następnie przekształcenie 'int' do' intptr_t' i z powrotem do 'int' może utraty informacji. W szczególności, jeśli wartość 'int' znajduje się poza zakresem' intptr_t', pierwsza konwersja daje wynik zdefiniowany przez implementację. –

+2

Niestety, przeczytaj odpowiedź niepoprawnie jako „Konwersja _pointer_ do' intptr_t' i tyłu jest mało prawdopodobne, aby stracić informacji ...”. Mój komentarz był oparty na tej myśli. Zgadzam się co do rzadkości problemów 'int/intptrt '. – chux

5

Nie, nie można zagwarantować, że każdy konkretny typ jest rozsądnym sposobem przechowywania obu wskaźników i liczb całkowitych, a poza tym, to sprawia, że ​​Twój kod mylące. Jest lepszy sposób.

Jeśli chcesz przechowywać liczbę całkowitą i wskaźnik w tym samym obiekcie, czyste i przenośny metodą jest użycie unii:

union foo { 
    int integer_foo; 
    void *pointer_foo; 
} 

To jest przenośny i pozwala na przechowywanie zarówno różne rzeczy w rozmiar pamięci potrzebnej dla większego z nich. To gwarantuje, że zawsze działa.

+1

Czy 'int' i' void * 'mają wspólny początkowy podciąg pod względem układu? W przeciwnym razie jest to _nie_ przenośne, nie masz _ pozwolenia na przechowywanie obu członków jednocześnie i jest to absolutnie _nie gwarantowane, aby "zawsze działało". –

+3

Co jest pewne, że brakuje definicji ';' po definicji związku. – Shoe

+1

@LightnessRacesinOrbit nie sądzę był twierdząc, że dwie wartości mogą być przechowywane w niej od razu. "oba" oznacza, że ​​"int" może być w nim przechowywane, a "void *" może być w nim przechowywane, ale nie ma sugestii jednoczesności. NB. Nie ma znaczenia, czy 'int' i' void * 'mają wspólną początkową sekwencję, ponieważ ta reguła dotyczy tylko struktur. –

Powiązane problemy