Pytanie Odlewanie dwa razy w tej samej linii


Widziałem ten kod w projekcie.

bjest typ void*:

void *b = ...;
int a = (int) (unsigned long) b;

Czy ta linia jest bezcelowa? Mam na myśli, to tak samo jak a = (int) b we wszystkich przypadkach?


14
2018-06-18 05:16


pochodzenie




Odpowiedzi:


To prawdopodobnie pozwala uniknąć ostrzeżenia kompilatora w 64-bitowych systemach Unix unsigned long to 64-bitowa ilość, a więc wystarczająco duża, by pomieścić wskaźnik, ale int jest 32-bitową ilością, która nie jest wystarczająco duża, aby pomieścić wskaźnik. Obsada do (unsigned long) zachowuje wszystkie bity adresu; kolejne odlewane do int wyrzuca 32-bitowe adresy o wysokim priorytecie, ale robi to bez domyślnego ostrzeżenia.

Aby zademonstrować:

int main(void)
{
    void *b = (void *)0x12345678;
    int   a = (int)(unsigned long)b;
    int   c = (int)b;
    return a + c;
}

$ gcc -O3 -g -std=c99 -Wall -Wextra -c ar.c
ar.c: In function ‘main’:
ar.c:5:15: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
$

Korzystając z GCC 4.7.1 na Mac OS X 10.8.4, domyślnie kompilacja 64-bitowa.

Interesujące jest spekulowanie, co zostanie zrobione z wartością "część adresu".


22
2018-06-18 05:23



Uwaga, kreatywni ludzie ukrywają informacje numeryczne (lub boolowskie) w void*s :) - hroptatyr
Czy to sprawia, że ​​jestem kreatywny - z przykładowym kodem, który pisałem podczas komentowania? - Jonathan Leffler
Hehe, naprawdę to robi, stąd +1 :) Poważnie, wiele API używa void* gdzie intptr_t byłoby właściwe - hroptatyr
I wiele API używa void * gdzie programiści korzystający z API będą lepiej obsługiwani przez nieprzejrzysty typ struktury: extern struct opaque *xyz_create(int); extern void xyz_free(struct opaque *);. Jeśli zastąpisz struct opaque z void *, każdy stary wskaźnik można przekazać do xyz_free() funkcja, ale z struct opaque, nie możesz przekazać do niego żadnego starego wskaźnika. - Jonathan Leffler
+1 za bycie kreatywnym :) Warto wspomnieć o innym problemie w oryginalnym kodzie, mianowicie o tym, że konwersja z typu bez podpisu na typ podpisany jest zdefiniowana przez implementację. Ponadto w twoim przykładowym kodzie nie potrzebujesz dwóch rzutów int. - Jens Gustedt


Bezpośrednie typowanie tekstu do wskaźnika na mniejszy typ mówi int może spowodować błąd kompilacji na niektórych kompilatorach (takich jak Clang) w środowisku 64-bitowym.

Na przykład:

 void *p = GetSomeAddress;
 int i = (int)p;  //error on compilers like Clang.

Rozwiązanie to:

int i = (int)(unsigned long)p;

lub

int i = (int)(long)p;

Dzieje się tak, ponieważ na platformie Unix, w modelu LP64, długość jest 64-bitowa.

Takie przypadki, musisz dokładnie sprawdzić, dlaczego potrzebujesz typecast od wskaźnika do int lub innego mniejszego typu, co może spowodować utratę danych.

To pytanie może ci również pomóc. Jak powinienem obsłużyć "cast from" void * "do" int "traci precyzję" podczas kompilowania 32-bitowego kodu na maszynie 64-bitowej?


1
2018-06-18 06:04





Widzę to także w moim projekcie.

W moim przypadku treść "b" jest wypełniona innymi źródłami / oprogramowaniem pośredniczącym używanymi do komunikacji między procesami.

Po wypełnieniu "b" program uzyska zawartość "b" z rzutem do właściwego pola "a". aplikacja następnie używa "a" do przetwarzania.

Mój projekt używa jednak znaku * zamiast pustki *.


0
2018-06-18 05:29