По определению, указатель void
указывает на объект типа «Я не уверен, какой тип объекта».
По определению, когда вы используете унарный оператор *
для доступаобъект, на который указывает указатель, вы должны знать (ну, компилятор должен знать), какой тип объекта.
Итак, мы только что доказали, что не можем напрямую разыменовать указатель void
, используя *
;мы всегда должны явным образом приводить указатель void
к какому-либо фактическому типу указателя объекта.
Теперь, в сознании многих людей, «очевидный» ответ на вопрос «на какой тип указывает / должен указывать« общий »указатель?»это "char
". И когда-то, до того, как был изобретен тип void
, указатели на символы обычно использовались в качестве «общих» указателей. Таким образом, некоторые компиляторы (включая, в частности, gcc) немного расширяют возможности и позволяют вам делать больше (например, арифметику указателей) с указателем void
, чем требует стандарт.
Так что может объясните, как такой код в вашем вопросе может "работать". (В вашем случае, тем не менее, поскольку указываемый тип был на самом деле int
, а не char
, если он "работал", это было только потому, что вы работали на машине с прямым порядком байтов.)
. ... И с учетом сказанного я обнаружил, что код в вашем вопросе не работает для меня, даже в gcc. Сначала он дает мне нефатальное предупреждение:
предупреждение: разыменование указателя 'void *'
Но затем он передумает и решает, что это ошибка:
ошибка: недопустимое использование выражения void
Второй протестированный мной компилятор сказал что-то похожее:
ошибка: неполный тип 'void'не присваивается
Приложение: Еще немного о , почему указательный тип используется повторно при разыменовании указателя:
КогдаВы получаете доступ к указателю, используя *
, компилятор будет выдавать код для извлечения (или, возможно, сохранения) в указанном месте. Но компилятору придется испускать код, который обращается к определенному количеству байтов, и во многих случаях может иметь значение, как эти байты интерпретируются. Количество и интерпретация байтов определяются типом (это типы для ), именно поэтому требуется фактический тип, не void
.
Один из лучших способов оценки этого требования, который я знаю, заключается в рассмотрении кода типа
*p + 1
или, что еще лучше,
*p += 1
Если p
указывает на char
,компилятор, вероятно, будет выдавать какую-то инструкцию addb
("add byte"). Если p
указывает на int
, компилятор выдаст обычную инструкцию add
. Если p
указывает на float
или double
, компилятор будет выдавать инструкцию сложения с плавающей точкой. И так далее.
Но если p
- это void *
, компилятор понятия не имеет, что делать. Он жалуется (в форме сообщения об ошибке) не только потому, что стандарт C говорит, что вы не можете разыменовать указатель void
, но, что более важно, потому что компилятор просто не знает, что делать с вашим кодом.