Końcowy wniosek: arytmetyka na a void*
jest niedozwolona zarówno w C, jak i C ++.
GCC dopuszcza to jako rozszerzenie, patrz Arytmetyka na void
- i wskaźnikach funkcji (zwróć uwagę, że ta sekcja jest częścią rozdziału „Rozszerzenia C” podręcznika). Clang i ICC prawdopodobnie zezwalają na void*
arytmetykę dla celów zgodności z GCC. Inne kompilatory (takie jak MSVC) nie zezwalają na arytmetykę void*
, a GCC nie zezwala na to, jeśli -pedantic-errors
flaga jest określona lub -Werror-pointer-arith
flaga jest określona (ta flaga jest przydatna, jeśli baza kodu musi również kompilować się z MSVC).
Mówi standard C.
Cytaty pochodzą z projektu n1256.
Standardowy opis operacji dodawania stwierdza:
6.5.6-2: W celu dodania oba operandy będą miały typ arytmetyczny lub jeden operand będzie wskaźnikiem do typu obiektu, a drugi będzie typu całkowitego.
Zatem pytanie tutaj brzmi, czy void*
jest to wskaźnik do „typu obiektu”, czy też równoważnie, czy void
jest to „typ obiektu”. Definicja „typu obiektu” to:
6.2.5.1: Typy są podzielone na typy obiektów (typy, które w pełni opisują obiekty), typy funkcji (typy opisujące funkcje) i typy niekompletne (typy, które opisują obiekty, ale brakuje im informacji potrzebnych do określenia ich rozmiarów).
A standard definiuje void
jako:
6.2.5-19: void
typ zawiera pusty zestaw wartości; jest to niekompletny typ, którego nie można ukończyć.
Ponieważ void
jest to niekompletny typ, nie jest to typ obiektowy. Dlatego nie jest poprawnym operandem do operacji dodawania.
Dlatego nie można wykonywać arytmetyki wskaźnika na void
wskaźniku.
Uwagi
Początkowo sądzono, że void*
arytmetyka jest dozwolona ze względu na następujące sekcje normy C:
6.2.5-27: Wskaźnik do void powinien mieć takie same
wymagania dotyczące reprezentacji i wyrównania , jak wskaźnik do typu znaku.
Jednak,
Te same
wymagania dotyczące reprezentacji i wyrównania mają implikować zamienność jako argumenty funkcji, wartości zwracane z funkcji i członków związków.
Oznacza to, że printf("%s", x)
ma to samo znaczenie, niezależnie x
od tego, czy ma typ, char*
czy void*
, ale nie oznacza to, że możesz wykonywać działania arytmetyczne na void*
.
Uwaga redaktora: ta odpowiedź została zredagowana, aby odzwierciedlić ostateczny wniosek.