2016-02-01 8 views
22

Co robi ((nazwa struct *) 0) -> członek) w C?Co robi ((nazwa struktury *) 0) -> członek) w C?

Rzeczywista oświadczenie C natknąłem było to:

(char *) &((struct name *)0)->member) 
+3

[Tak] (https://stackoverflow.com/questions/7180290/how-do-you-use-offsetof-on-a-ctct), [many] (https: // stackoverflow.com/questions/713963/why-does-this-implementation-of-offsetof-work), [duplikaty] (https://stackoverflow.com/questions/6700114/portability-of-using-stddef-hs-offsetof-rather -tak-toczenie-własne). – 2501

+1

I jego (niezdefiniowane) zachowanie: https://stackoverflow.com/questions/26906621/does-struct-name-null-b-cause-undefined-behaviour-in-c11 – 2501

+0

Nie chcę się dowiedzieć o offsetach() tutaj. Jestem szczególnie zainteresowany wiedzą, jak działa dane stwierdzenie. To nie jest duplikat IMHO – krisharav

Odpowiedz

25

Jest to sztuczka polegająca na uzyskaniu przesunięcia elementu o nazwie struct o nazwie member. Ideą tego podejścia jest skompilowanie przez kompilator adresu member przy założeniu, że sama struktura znajduje się pod adresem zero.

Korzystanie offsetof oferuje bardziej czytelny alternatywę dla tej składni:

size_t offset = offsetof(struct name, member); 
+0

fajnie! dzięki za wskaźnik do strony wiki. które nie pojawiły się w Google :) – krisharav

+1

Ale czy nie jest niezdefiniowanym zachowaniem dereferencji o zerowym wskaźniku? –

+3

nie usuwasz go właściwie. Samo uzyskanie adresu. – krisharav

5

(struct name *)0 rzuca 0 do wskaźnika do struct name.
&((struct name *)0)->member) otrzymuje adres członka member.
(char *) &((struct name *)0)->member) przesyła ten adres pod numer char *.

W przypadku, gdy ktoś myśli, że powyższe wyrażenie usuwa odwołanie do wskaźnika NULL, należy pamiętać, że nie ma tutaj dereferencji. To wszystko za uzyskanie adresu członka number.

+0

Czy '(nazwa struktury *) 0' jest takie samo jak' i nazwa struktury + 0'? –

+2

@CoolGuy - nie, ponieważ '& nazwa struct' nie jest legalne C, ponieważ nie można przyjąć adresu typu. – LThode

+0

Jak rzutowanie '0' na coś legalnego? '0' jest liczbą całkowitą, a nie bitem zerowym, prawda? Możesz po prostu rzucić '0' lub' 7' lub ''\ n''do losowych wskaźników struktury? – user1717828

5

(struct name*)0 daje wskaźnik struct.

((struct name*)0)->member podaje członka struktury, do której wskazuje wskaźnik.

Dodawanie & daje adres tego członka, a wreszcie

(char *) jest rzucić uzyskany adres do wskaźnika char.

1

W wielu kompilatorów, powyższe wyrażenie przyniesie char* która jednocześnie nie jest ważny wskaźnik, posiada jedną lub obydwie z poniższych właściwości:

  1. Casting wskaźnik bezpośrednio do całkowitej type da przesunięcie wskazanego elementu w strukturze.

  2. Odjęcie od wskaźnika (char*)0 spowoduje przesunięcie wskazanego elementu w strukturze.

Należy zauważyć, że C standard nakłada żadnych wymagań w odniesieniu do tego, co może się zdarzyć, jeśli kod tworzy nieprawidłową wartość wskaźnika za pomocą powyższych środków lub jakakolwiek inna, nawet jeśli kod nie próbuje nieprawidłowego wskaźnika. Podczas gdy wiele kompilatorów tworzy wskaźniki o wskazanych właściwościach, takie zachowanie nie jest uniwersalne. Nawet na platformach, gdzie istnieje wyraźna naturalna zależność między wskaźnikami a liczbami całkowitymi, niektórzy dostawcy kompilatorów mogą zdecydować, że posiadanie programów zachowuje się jak sugerowane przez taką relację, byłoby bardziej "wydajne" zamiast tego, aby kompilator zakładał, że program nigdy nie będzie otrzymywać dane wejściowe, które powodowałyby generowanie nieprawidłowych wskaźników, a co za tym idzie, każdy kod, który byłby istotny tylko w przypadku otrzymania takich danych wejściowych, powinien zostać pominięty.