Подтвердить что ты не робот

Могу ли я сделать арифметику на указателях void * в C?

- это действительный

void *p = &X; /* some thing */
p += 12;

и если да, то на что указывает p? У меня есть (сторонний) код, который делает это (и компилируется чисто), и я предполагаю, что void * рассматривался как char *. Мой надежный K & R не работает (ish) по теме

EDIT: мое маленькое тестовое приложение отлично работает на gcc 4.1.1 и обрабатывает void * как char *. Но g++ barfs

Я знаю, как это сделать правильно. Мне нужно знать, нужно ли мне очищать эту базу кода, чтобы найти все места, которые она сделала.

BTW gcc -pedantic выдает предупреждение

Резюме:

Спецификация C неоднозначна. В нем говорится, что в терминах представления и использования в качестве параметров функции void * = char *. Но он молчал относительно арифметики указателя.

  • gcc (4) разрешает это и рассматривает его как char *
  • g++ отказывается от него
  • gcc -pedantic предупреждает об этом
  • vs2010 и c и С++ отказывается от него.
4b9b3361

Ответ 1

Это зависит от компилятора. Те, которые позволяют ему рассматривать sizeof (* (void *)) как 1.

EDIT: это только для арифметики указателей пустот. Было бы бесполезно использовать в этом случае шаги sizeof (int) или 0. Общим ожиданиям того, кто его использует, был бы наименьший возможный шаг.

Ответ 2

Нет, это не законно. A void* не может быть произвольно увеличен. Сначала его нужно перенести на определенный тип.

Если вы хотите увеличить его на определенное количество байтов, то это решение, которое я использую.

p = ((char*)p) + 12;

Тип char удобен, поскольку он имеет размер 1 байт.

EDIT

Интересно, что он работает на gcc с предупреждением. Я тестировал Visual Studio 2010 и проверял, что он не компилируется. Мое ограниченное понимание стандарта скажет, что gcc в ошибке здесь. Можете ли вы добавить следующие флаговые компиляции

-Wall -ansi -pedantic

Ответ 3

Процитировать по спецификации:

§6.5.6/2. Для добавления оба операнда должны иметь арифметический тип, или один операнд должен быть указателем на тип объекта, а другой должен иметь целочисленный тип. (Инкремент эквивалентен добавлению 1.)

Указатель на void не является указателем на тип объекта, в соответствии с этими выдержками:

§6.2.5/1: [...] Типы разделены на типы объектов (типы, которые полностью описывают объекты), типы функций (типы описывающие функции) и неполные типы (типы, описывающие объекты, но не имеющие информация, необходимая для определения их размеров).

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

Следовательно, арифметика указателя не определена для указателя на типы void.

Ответ 4

Ваша догадка правильная.

В стандарте ISO C99, раздел 6.2.5, пункт 26, он заявляет, что указатели void и указатели на символы будут иметь те же требования к представлению и выравниванию (перефразирование).

Ответ 6

Я не думаю, что вы можете, потому что он не знает своего типа, поэтому не может найти правильное количество байтов.

Сначала переведите его в тип, т.е. (int).