Арифметика указателя для указателя void в C

Когда указатель на определенный тип (скажем int, char, float,..) увеличивается, его значение увеличивается на размер этого типа данных. Если указатель void, который указывает на данные размера x, увеличивается, как он достигает точки x байтов впереди? Как компилятор знает, чтобы добавить x в значение указателя?

Ответ 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*.

Примечание редактора: Этот ответ был отредактирован, чтобы отразить окончательный вывод.

Ответ 2

В указателях void* не указана арифметика указателя.

Ответ 3

Вы не можете выполнить арифметику указателя на типах void *, именно по этой причине!

Ответ 4

передайте его указателю char, чтобы увеличить указатель вперед вперед x байтов.

Ответ 5

Перед выполнением арифметики указателя вы должны передать его другому типу указателя.

Ответ 6

Указатели Void могут указывать на любой фрагмент памяти. Следовательно, компилятор не знает, сколько байтов для увеличения/уменьшения при попытке арифметики указателя на указателе пустоты. Поэтому указатели void должны быть сначала приведения типов к известному типу, прежде чем они могут быть вовлечены в любую арифметику указателя.

void *p = malloc(sizeof(char)*10);
p++; //compiler does how many where to pint the pointer after this increment operation

char * c = (char *)p;
c++;  // compiler will increment the c by 1, since size of char is 1 byte.

Ответ 7

Компилятор знает по типу. Учитывая void *x:

  • x+1 добавляет один байт к x, указатель переходит к байту x+1
  • (int*)x+1 добавляет sizeof(int) байты, указатель переходит к байту x + sizeof(int)
  • (float*)x+1 addres sizeof(float) байты, и др.

Хотя первый элемент не является переносимым и противоречит Galateo C/С++, он тем не менее корректен на языке C, то есть он скомпилирует что-то на большинстве компиляторов, возможно, требуя соответствующего флага (например, -Wpointer-arith)

Ответ 8

Стандарт C не позволяет арифметику указателя void. Тем не менее, GNU C разрешено, учитывая размер void - 1.

C11 standard §6.2.5

Пункт - 19

Тип void содержит пустой набор значений; это неполное тип объекта, который не может быть завершен.

Следующая программа работает отлично в компиляции GCC.

#include<stdio.h>

int main()
{
    int arr[2] = {1, 2};
    void *ptr = &arr;
    ptr = ptr + sizeof(int);
    printf("%d\n", *(int *)ptr);
    return 0;
}

Может быть, другие компиляторы генерируют ошибку.