вот так:
void** a = calloc(4,4);
printf("%x,%x",a,a+1));
результат
1516c0,1516c8
почему шаг 8? Я не хочу использовать (char*) для преобразования типа, что мне делать?
вот так:
void** a = calloc(4,4);
printf("%x,%x",a,a+1));
результат
1516c0,1516c8
почему шаг 8? Я не хочу использовать (char*) для преобразования типа, что мне делать?
Я полагаю, что у вас проблемы с пониманием разницы между физическими адресами и ссылками. Арифметика указателей в C выполняется с использованием объектов, на которые ссылаются указатели. Когда вы печатаете указатель, используя "%p" или "%x" (нехорошо, поскольку это неправильный формат), вы получаете физический (байтовый) адрес.
Вы, вероятно, используете void **
, потому что арифметика указателей на void *
не работает на большинстве компиляторов, которые не имеют специальных расширений, таких как gcc
.
Если вы хотите увеличить address
на единицу, просто используйте указатель char *
вместо void *
Если вы хотите напечатать разницу в арифметике указателя (не физические байты):
int main(void)
{
void **a;
printf("%" PRIiPTR "\n", a - (a+1));
}
Как уже упоминалось, размер void *
в вашей системе равен 8, поэтому он идет на 8 байт вперед. В любом случае, вам просто нужно что-то изменить, и вам не нужно использовать char *
для этого случая. Кроме того, лучше использовать %p
для печати указателей:
void** a = calloc(4, sizeof(void *));
printf("%p,%p",a,a+1));
Печать указателей с %x
определена некорректно, вместо этого следует использовать %p
.
a+1
выполняет арифметические действия с указателем для типа void**
, то есть вы получаете размер в байтах элемента, на который указывает указатель, a void*
. Таким образом, в зависимости от того, насколько велик такой указатель в вашей системе, вы получите соответствующее изменение адреса. По-видимому, ваша система имеет 64-битные указатели (вероятно, 64-битная адресная шина), следовательно, 8 байтов.
Использование абсолютных значений для calloc
в целом является подозрительным кодом. Не уверен, чего вы пытаетесь достичь с помощью этого.
Если вам нужен универсальный указатель типа, который может перебирать общие фрагменты данных байт за байтом, правильный тип для использования — unsigned char*
. Если вы не хотите использовать это по каким-то искусственным причинам, то, к сожалению, ничего не получится.
с каких пор арифметика на void* определена?
@Raildex Начиная с первого стандарта C? Это арифметика приводит к указанному void
, который не определен. Таким образом, если бы это было void* a
, код не скомпилировался бы. Однако void**
— это обычный тип указателя без специальных правил.
да, я хотел бы использовать «универсальный тип» в c, потому что размер некоторого типа меньше 8 байт, например: int равен 4 байтам, я хочу перемещать указатель байт за байтом. Я использую (char*) , он работает довольно хорошо. Нужно ли его менять?
@GuoHaodong Это то, что я написал в ответ, да? За исключением того, что это должно быть unsigned char*
, если вы хотите получить доступ к данным через этот указатель. char*
имеет подписанность, определяемую реализацией, и поэтому его не следует использовать при работе с необработанными двоичными данными.
Арифметика указателя.
sizeof (void *)
в вашей системе равно 8, поэтомуa + 1
идет на 8 байт вперед, чтобы перейти к следующемуvoid *
. Также правильным спецификатором формата для указателей является%p
.Добро пожаловать в СО. Вы забыли важные детали. Какой шаг вы ожидали? 4? 1? Почему? "что я должен делать?" Чего вы хотите достичь?
Как упоминалось в mediocrevegetable1, для указателей требуется спецификатор формата
%p
. И, чтобы быть точным, вы должны указатьvoid*
, что означает, что вам нужно преобразовать вашvoid**
вvoid*
для его печати.Как и при индексации массива, добавление 1 перемещает к следующему элементу, а не к следующему байту.
a + 1
совпадает с&a[1]
.Я хочу, чтобы шаг стал 1
Шаг за шагом 1 что? Для чего? Добавление
1
делает шаг за шагом 1. Зачем вамcalloc(4,4)
, когда размер указателя в вашей системе явно8
?Используйте
%p
для печати значений указателя, а не%x
. В типичной 64-битной системе указатели имеют размер 8 байтов, а целые числа — 4 байта, поэтому в лучшем случае вы будете печатать только половину указателей, а второй указатель может вообще не печататься.«Я хочу, чтобы шаг стал 1». Менее ужасные решения для этого включают «использование (char *) для преобразования типа», чего вы НЕ хотите. Пожалуйста, решите, какое из этих двух требований важнее. Вы также можете сделать один логический шаг назад и описать, чего вы действительно хотите достичь, т. е. подумайте, смотрим ли мы на meta.stackexchange.com/questions/66377/what-is-the-xy-problem.
a+1
зависит от типаa
, а не от адресаa
(ни от количества байтов, зарезервированных по этому адресу).арифметика указателя на
void*
недопустима. Дубликат: Арифметика указателя для указателя void в C, Должен ли компилятор предупреждать об арифметике указателя с указателем void?, Почему приращение указателя на один байт перемещается вперед на 1 но это 4 байта для целочисленного указателя, 8 для двойного?Однако арифметика указателя @phuclv на
void**
не работает.