Когда указатель к определенному типу (скажем int
, char
, float
, ..) увеличивается, его значение увеличивается на размер этого типа данных. Если void
указатель, который указывает на данные размера x
, увеличивается, как он может указывать x
вперед байты? Как компилятор знает, как добавить x
значение указателя?
c
pointers
void-pointers
pointer-arithmetic
Шива Шанкаран
источник
источник
void
указатель, который указывает на данные размераx
, увеличивается, как он может указыватьx
байты вперед?» Это не так. Почему люди, у которых есть такие вопросы, не могут их проверить, прежде чем спросить - вы знаете, по крайней мере, до минимума, когда они проверяют, действительно ли он компилируется, а это не так. -1, не могу поверить, что получил +100 и -0.Ответы:
Окончательный вывод: арифметика на
void*
это незаконно и в C и C ++.GCC допускает это как расширение, см. Арифметические
void
и функциональные указатели (обратите внимание, что этот раздел является частью главы «Расширения C» в руководстве). Clang и ICC, вероятно, разрешаютvoid*
арифметику в целях совместимости с GCC. Другие компиляторы (такие как MSVC) не разрешают арифметикуvoid*
, и GCC запрещает ее, если-pedantic-errors
указан флаг или-Werror-pointer-arith
указан флаг (этот флаг полезен, если ваша кодовая база также должна компилироваться с MSVC).Стандарт C говорит
Цитаты взяты из проекта N1256.
Стандартное описание операции сложения гласит:
Таким образом, вопрос здесь заключается в том, является ли
void*
указатель на «тип объекта» или, что эквивалентно,void
является ли «тип объекта». Определение типа объекта:И стандарт определяет
void
как:Поскольку
void
это неполный тип, это не тип объекта. Поэтому он не является допустимым операндом для операции сложения.Поэтому вы не можете выполнять арифметику указателя на
void
указателе.Ноты
Первоначально считалось, что
void*
арифметика была разрешена из-за этих разделов стандарта C:Тем не мение,
Таким образом, это означает, что
printf("%s", x)
имеет то же значение,x
имеет ли типchar*
илиvoid*
, но это не означает, что вы можете делать арифметику наvoid*
.Примечание редактора: этот ответ был отредактирован, чтобы отразить окончательный вывод.
источник
void*
арифметика указателей не допускается. GCC имеет расширение, которое позволяет это делать.void*
арифметику (по крайней мере, по умолчанию).Арифметика
void*
указателей на указатели не допускается .источник
void
является неполным типом, который никогда не может быть завершен по определению.приведите его к указателю на символ, увеличивая указатель вперед на х байт вперед.
источник
char
, увеличение наx
, а затем переосмысление нового значения, поскольку некоторый другой тип является бессмысленным и неопределенным поведением.man 3 qsort
должна иметьvoid qsort(void *base, size_t nmemb, size_t size, [snip])
, то у вас нет никакого способа узнать «правильный тип»Стандарт C не допускает арифметику пустых указателей. Тем не менее, GNU C допускается с учетом размера пустот IS
1
.Стандарт С11 §6.2.5
Абзац 19
Следующая программа работает нормально в компиляторе GCC.
Может быть другие компиляторы генерируют ошибку.
источник
Вы не можете делать арифметику указателей на
void *
типах, именно по этой причине!источник
Вы должны привести его к другому типу указателя, прежде чем выполнять арифметику указателя.
источник
Пустые указатели могут указывать на любой фрагмент памяти. Следовательно, компилятор не знает, сколько байтов будет увеличиваться / уменьшаться, когда мы пытаемся использовать арифметику указателя на пустом указателе. Поэтому указатели типа void должны быть сначала приведены к известному типу, прежде чем они могут быть включены в любую арифметику указателей.
источник
Компилятор знает тип приведения. Учитывая
void *x
:x+1
добавляет один байтx
, указатель переходит на байтx+1
(int*)x+1
добавляетsizeof(int)
байты, указатель переходит на байтыx + sizeof(int)
(float*)x+1
адресаsizeof(float)
байтов и т. д.Несмотря на то, что первый элемент не переносим и не соответствует Galateo C / C ++, он, тем не менее, корректен на языке C, что означает, что он будет компилироваться во что-то на большинстве компиляторов, возможно, требующих соответствующего флага (например, -Wpointer-arith)
источник
Althought the first item is not portable and is against the Galateo of C/C++
Правда.it is nevertheless C-language-correct
Ложь. Это двойное мышление! Арифметика указателей наvoid *
синтаксически недопустима, не должна компилироваться и выдает неопределенное поведение, если это так. Если неосторожный программист может заставить его скомпилировать, отключив какое-то предупреждение, это не оправдание.unsigned char*
например, для добавленияsizeof
значения в указатель.