Wyjaśnienie kodu rzutowania wskaźnika generycznego

0

Witam. Nie mogę zrozumieć jednej linijki z poniższego kodu:

#include <iostream>

using namespace std;

int main()
{
    int telefon = 12345;    //zmienna liczbowa
    void *wsk = &telefon;   //wskaźnik generyczny wsk typu void

    *(int*)wsk = 666;

    cout << *(int*)wsk << endl;

    return 0;
}

Chodzi o linijkę gdzie jest (int)wsk=666.
Wygląda to prawie jak rzutowanie.
Dlaczego to nie jest jako np. *(int)wsk albo (int)*wsk? Czemu jedna znak wyłuskania jest na samym początku przed nawiasem, i w nawiasie na końcu?
O co w tym chodzi?

0

void oznacza brak typu (z ang. próżnia/pustka/nic), więc nie można mu przypisać wartości. Dlatego trzeba powiedzieć komplikatorowi jak ma go potraktować (int*)wsk. Skoro komplikat0r wie co to jest to można już na tym działać. Z wskaźnika na void zrobił się WSKAŹNIK NA INT. Nie chcemy zmienić wskaźnika, tylko przypisać wartość "temu czemuś" na co on wskazuje, więc musimy go wyłuskać *(int*)wsk.

1

@adrian.widzew rozbij to na 2 instrukcje i będzie bardziej czytelnie ;)

int telefon = 12345;
void *wsk = &telefon;
int* wsk_na_int = (int*)wsk
*wsk_na_int = 666;
0

Dzięki Shalom za tą propozycję z rozbiciem tego na 2 instrukcję. Na stronie z której o tym czytałem, autor nie rozbił tego czegoś. Ale i tak nie bardzo kumam ten zapis (int*)wsk. Jakby nie było tego nawiasu to by był zwykły wskaźnik do typu int. Chyba, że to jest sposób na rzutowanie wskaźnika do typu void na wskaźnik do typu int. Ale to i tak nie wiem czy nie powinno być (int)*wsk. Przecież to też rzutowanie, i wyszłoby to samo chyba.
Czyli obecnie po rozbiciu tego czegoś, rozchodzi się tylko o tą gwiazdkę w nawiasie co siedzi.

0

To jest właśnie rzutowanie. Zauważ że
(int)wsk
to ZUPEŁNIE co innego niż
(int
)wsk
W pierwszym przypadku masz operator rzutowania (int) wywołany na wsk czyli na obszarze pamięci pokazywanym przez wsk. Czyli to w teorii zrzutowałoby WARTOŚĆ pod wskaźnikiem wsk na inta. Ale nie wolno ci robić wsk bo wskaźnik wsk nie ma typu, więc nie da sie "odczytać z niego wartości", bo nie wiesz ile bajtów należałoby odczytać. Jak masz wskaźnik char to wiadomo że wartość to 1 bajt, jak masz int to wiadomo że (zwykle) wartość to 4 bajty, ale dla void* nie wiadomo nic.
W drugim przypadku masz operator rzutowania (int*) wywołany na wsk czyli na adresie pokazywanym przez wsk. Czyli chcesz rzutować wskaźnik na wskaźnik do int.

Widzisz różnicę między tymi dwoma typami danych: int oraz wskaźnik do int? Jeden przechowuje liczby, drugi przechowuje adresy :)

0

Czyli rzutowanie wskaźnika do typu void na wskaźnik do typu int. Dobra. Będzie chyba trzeba zapamiętać ten sposób zapisu. Rzutowanie wskaźnika na inny wskaźnik. To jeśli miałbym przykładowo jeden wskaźnik do typu int, i chciałbym go rzutować na wskaźnik do typu long to musiałbym zapisać coś takiego: (long*)wskaznik_int .

To może ktoś mi powie po co to stosować? Jakby nie można było od razu ustalić wskaźnik do odpowiedniego typu

1

Tego sie nie stosuje. Jedyny przypadek to rzutowania na wskaznik do unsigned char char.

Przeklejam komentarz od @Endrju, ze wzgledu na to, ze malo osob je czyta:

Oczywiście nie, bo to jest undefined bahvior (przez strict aliasing). char jest ok i nie musi być unsigned.

1
  1. Tak, tak to będzie wyglądać.
  2. Cóż, powodów jest całkiem sporo. Szczególnie kiedy bawisz się w przetwarzanie danych binarnych. Ostatnio pisałem projekt z tym związany (co prawda pisałem go w Pythonie, ale używałem c_types). Wyobraź sobie że wczytujesz sobie na przykład 1MB binarnych danych i następnie na podstawie jakiegoś algorytmu możesz dopiero "rozkodować" te dane. Dane mogą mieć różną liczbę bitów (1-64) i mogą też reprezentować różne typy danych (int, float, double, singned, unsigned). Nie jesteś w stanie w żaden sposób tego stwierdzić w czasie czytania danych, bo na dysku masz po prostu megabajt zer i jedynek ;) Wykrawasz więc sobie kawałki tych binarnych danych i rzutujesz na odpowiednie typy.
0

Chyba, że tak z prostszych przykładów, wręcz najprostszych sprawdzać jaką wartość podał użytkownik, i później dopasować odpowiedni typ zmiennej do tego. Jak int za mały to ustawić np. wskaźnik long.

1 użytkowników online, w tym zalogowanych: 0, gości: 1