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