Ответ 1
Окончательный вывод: арифметика на void*
незаконна как в C, так и в С++.
GCC разрешает его как расширение, см. Арифметика на void
и указателях функций (обратите внимание, что этот раздел является частью "C Extensions" главы руководства). 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*
.
Примечание редактора: Этот ответ был отредактирован, чтобы отразить окончательный вывод.