Окончательный вывод: арифметика на void*
является незаконной как в C, так и в C ++.
GCC разрешает ее как расширение, см. Арифметика на void
- и указатели функций (обратите внимание, что этот раздел является частью главы «C Расширения» руководства). Clang и ICC, вероятно, разрешают арифметику void*
для совместимости с GCC. Другие компиляторы (такие как MSVC) отклоняют арифметику на void*
, а GCC запрещает ее, если указан флаг -pedantic-errors
, или если указан флаг -Werror-pointer-arith
(этот флаг полезен, если ваша база кода также должна компилироваться с помощью MSVC ).
Котировки берутся из черновика n1256.
Стандартное описание состояний операции добавления:
6.5.6-2: Для добавления оба операнда должны иметь арифметический тип, или один операнд должен быть указателем на тип объекта, а другой должен иметь целочисленный тип.
blockquote>Итак, вопрос в том, является ли
void*
указателем на «тип объекта» или, что то же самое, является лиvoid
«типом объекта». Определение для «типа объекта»:6.2.5.1: Типы разделены на типы объектов (типы, которые полностью описывают объекты), типы функций (типы, описывающие функции) и неполные типы (типы, которые описывают объекты, но не имеют информации, необходимой для определения их размеров).
blockquote>И стандарт определяет
void
as:6.2.5-19: Тип
blockquote>void
содержит пустой набор значений; это неполный тип, который не может быть завершен.Поскольку
void
является неполным, он не является типом объекта. Поэтому он не является допустимым операндом операции сложения.Поэтому вы не можете выполнить арифметику указателя на указателе
void
.Примечания
Первоначально он считалось, что арифметика
void*
разрешена из-за этих разделов стандарта C:6.2.5-27: указатель на void должен иметь те же требования к представлению и выравниванию, что и указатель для символьного типа.
blockquote>Однако
Те же требования к представлению и выравниванию подразумевают взаимозаменяемость в качестве аргументов функций, возврат значений из функций и члены союзов.
blockquote>Итак, это означает, что
printf("%s", x)
имеет то же значение, чтоx
имеет типchar*
илиvoid*
, но это не означает, что вы можете сделать арифметику наvoid*
.Примечание редактора: этот ответ был отредактирован, чтобы отразить окончательный вывод.