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-errorsflaga jest określona lub -Werror-pointer-arithflaga 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 voidjest 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 voidjako:
6.2.5-19: voidtyp zawiera pusty zestaw wartości; jest to niekompletny typ, którego nie można ukończyć.
Ponieważ voidjest 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 voidwskaź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 xod 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.