void pointer

User avatar
thinker
Уже с Приветом
Posts: 26871
Joined: 29 Aug 2000 09:01

void pointer

Post by thinker »

как правильно создать void pointer in C:

void *ptr;

или

void* ptr;

Вижу и так и так пишуть. Или ето одно и тоже? совсем запутался...
All rights reserved, all wrongs revenged.
OtherSide
Уже с Приветом
Posts: 15770
Joined: 01 Mar 2008 15:14

Re: void pointer

Post by OtherSide »

и так и так правильно
User avatar
venco
Уже с Приветом
Posts: 2001
Joined: 10 Nov 2004 00:34
Location: MD

Re: void pointer

Post by venco »

Это одно и то же. Пробелы в C влияют только на разделение токенов, ну и в строках, конечно.
Можно даже написать:

Code: Select all

void
*
ptr
;
Первый вариант лучше тем, что тип отделён от имени переменной.
Второй вариант лучше в случае объявления нескольких переменных, т.к. звёздочка относится таки к идентификатору, а не void.
Например в коде:

Code: Select all

int* ptr1, ptr2;
ptr1 - указатель, а ptr2 - нет.
Дабы не смущать человеческий парсер лучше писать:

Code: Select all

int *ptr1, *ptr2;
или вообще не объявлять несколько указателей в одной строке.
User avatar
thinker
Уже с Приветом
Posts: 26871
Joined: 29 Aug 2000 09:01

Re: void pointer

Post by thinker »

ок, спасибо. Правильно ли я понимаю что две строки ниже тоже одно и тоже:

Code: Select all

int CmpFunc(const void* _a, const void* _b) { ...}
int CmpFunc(const void *_a, const void *_b) { ...}
и здесь

Code: Select all

const float* a = (const float*) _a;
const float *a = (const float *) _a;
All rights reserved, all wrongs revenged.
User avatar
venco
Уже с Приветом
Posts: 2001
Joined: 10 Nov 2004 00:34
Location: MD

Re: void pointer

Post by venco »

Да.
OtherSide
Уже с Приветом
Posts: 15770
Joined: 01 Mar 2008 15:14

Re: void pointer

Post by OtherSide »

Секундочку.. Вообще-то ведь нельзя указатель на Void создать. Как можно создать указатель на участок памяти размерностью 0
User avatar
Dmitry67
Уже с Приветом
Posts: 28294
Joined: 29 Aug 2000 09:01
Location: SPB --> Gloucester, MA, US --> SPB --> Paris

Re: void pointer

Post by Dmitry67 »

OtherSide wrote:Секундочку.. Вообще-то ведь нельзя указатель на Void создать. Как можно создать указатель на участок памяти размерностью 0
Эх, молодежь...
Зарегистрированный нацпредатель, удостоверение N 19719876044787 от 22.09.2014
User avatar
thinker
Уже с Приветом
Posts: 26871
Joined: 29 Aug 2000 09:01

Re: void pointer

Post by thinker »

OtherSide wrote:Секундочку.. Вообще-то ведь нельзя указатель на Void создать. Как можно создать указатель на участок памяти размерностью 0
размерность будет не ноль а такая, на которую указывает void pointer.
All rights reserved, all wrongs revenged.
OtherSide
Уже с Приветом
Posts: 15770
Joined: 01 Mar 2008 15:14

Re: void pointer

Post by OtherSide »

И то правда, у меня уже мозги от собеседований едут. Недавно спрашивали, что будет если сделать (void*)++
User avatar
AndreyT
Уже с Приветом
Posts: 3000
Joined: 14 Apr 2004 01:11
Location: SFBA (было: Минск, Беларусь)

Re: void pointer

Post by AndreyT »

OtherSide wrote:Секундочку.. Вообще-то ведь нельзя указатель на Void создать. Как можно создать указатель на участок памяти размерностью 0
А в чем проблема? Указатель типа `void *` указывает на безразмерную точку в памяти. `void` является неполным типом, и у него нет размера. Поэтому разадресовать `void *` указатель нельзя и применять адресную арифметику к `void *` указателю нельзя. А вот сранивать такие указатели (в рамках общих органичений) можно. Ну и, понятное дело, приводить их к другим указательным типам можно.
OtherSide wrote:Недавно спрашивали, что будет если сделать (void*)++
В языке С оператор `++` к указателю типа `void *`не применим. Но вопрошающие могут быть испрочены GNU-расширениями, в которых разрешается применять адресную арифметику к `void *`. Последний при этом ведет себя как `char *`.
Best regards,
Андрей
User avatar
thinker
Уже с Приветом
Posts: 26871
Joined: 29 Aug 2000 09:01

Re: void pointer

Post by thinker »

AndreyT wrote:
OtherSide wrote:Секундочку.. Вообще-то ведь нельзя указатель на Void создать. Как можно создать указатель на участок памяти размерностью 0
А в чем проблема? Указатель типа `void *` указывает на безразмерную точку в памяти.
Вы про какой язык? Если про C, то void pointer означает что pointer может указывать на любой тип данных. Размер етих данных вполне определенный:

Code: Select all

void *ptr;    // ptr is declared as Void pointer

char cnum;
int inum;
float fnum;

ptr = &cnum;  // ptr has address of character data
ptr = &inum;  // ptr has address of integer data
ptr = &fnum;  // ptr has address of float data
All rights reserved, all wrongs revenged.
User avatar
AndreyT
Уже с Приветом
Posts: 3000
Joined: 14 Apr 2004 01:11
Location: SFBA (было: Минск, Беларусь)

Re: void pointer

Post by AndreyT »

thinker wrote:
AndreyT wrote:
OtherSide wrote:Секундочку.. Вообще-то ведь нельзя указатель на Void создать. Как можно создать указатель на участок памяти размерностью 0
А в чем проблема? Указатель типа `void *` указывает на безразмерную точку в памяти.
Вы про какой язык? Если про C, то void pointer означает что pointer может указывать на любой тип данных. Размер етих данных вполне определенный:
Я вам про Фому, а вы мне про Ерему.

Язык С - это язык со статической типизацией. С точки зрения языка `void *` указывает на неполный тип `void`. Это некое абстарктной положение - точка - в памяти и не более. Это все что интересно языку.

А то, что вы там лично знаете, что на самом деле в этом месте хранится какой-то объект типа `float` - это языку С не интересно. Никаких фич, основанных на этом факте, в языке С нет и быть не может. Если вы лично знаете, что ваш `void *` указывает на какой-то объект типа `float`, то доступиться к этому объекту типа `float` вы сможете только после приведения `void *` к типу `float *`. Но с этого момента вы уже не работатете с `void *`, а работаете с `float *`.

С таким же успехом вы можете использовать указатель `int *` для того, чтобы указывать на объект типа `float`. Преобразуйте типы указателей - и готово. Язык вам этого не запрещает. Вы-то при этом будуте знать, что указатель `int *` фактически указывает на `float`, но языку до этого никакого дела нет. Язык будет считать, что `int *` указывает на `int` со всеми вытекающими.
Best regards,
Андрей
User avatar
thinker
Уже с Приветом
Posts: 26871
Joined: 29 Aug 2000 09:01

Re: void pointer

Post by thinker »

AndreyT wrote:Язык С - это язык со статической типизацией. С точки зрения языка `void *` указывает на неполный тип `void`. Это некое абстарктной положение - точка - в памяти и не более. Это все что интересно языку.
Это интересно прежде всего мне, а не языку. Язык - это инструмент, как например, рубанок для плотника. Что можно быть интересно рубанку??? :pain1:

После ptr = &fnum;
мы имеем не абстракную точку в памяти, а вполне конкретный (физический) адрес, где храниться перенная fnum и тип етой переменной float. Именно этот адрес меня и интересует чтобы в какой-то момент изменить значение данной переменной по данному адресу.
All rights reserved, all wrongs revenged.
User avatar
AndreyT
Уже с Приветом
Posts: 3000
Joined: 14 Apr 2004 01:11
Location: SFBA (было: Минск, Беларусь)

Re: void pointer

Post by AndreyT »

thinker wrote:мы имеем не абстракную точку в памяти, а вполне конкретный (физический) адрес, где храниться перенная fnum и тип етой переменной float. Именно этот адрес меня и интересует
чтобы в какой-то момент изменить значение данной переменной по данному адресу.
Темой обсуждения пока что являлся указатель типа `void *`. Никакого доступа ни к какой переменой типа `float` указатель типа `void *` вам предоставить не может. Доступ к переменной типа `float` может предоставить только указатель типа `float *`. Интересно это вам или не интересно - вопрос посторонний.

А рассуждения типа "из указателя типа `void *` я могу получить указатель типа `float *`, а это значит, что доступ к переменной типа `float` предоставлен именно указателем типа `void *`" - это примерно то же самое, что заявлять, что доступ к переменным типа `float` мне сегодня предоставил велосипед, так как я на нем на работу приехал.

P.S. "Конкретный (физический) адрес" - это то же самое, что "абстракная точка в памяти". Словом "абстрактная" я лишь подчеркиваю нетипизированность указателя `void *`, не более.
Best regards,
Андрей
User avatar
thinker
Уже с Приветом
Posts: 26871
Joined: 29 Aug 2000 09:01

Re: void pointer

Post by thinker »

AndreyT wrote:Если вы лично знаете, что ваш `void *` указывает на какой-то объект типа `float`, то доступиться к этому объекту типа `float` вы сможете только после приведения `void *` к типу `float *`.
OK, в каком месте вышеуказанного кода мы приводим `void *` к типу `float *` ?
All rights reserved, all wrongs revenged.
User avatar
AndreyT
Уже с Приветом
Posts: 3000
Joined: 14 Apr 2004 01:11
Location: SFBA (было: Минск, Беларусь)

Re: void pointer

Post by AndreyT »

thinker wrote:
AndreyT wrote:Если вы лично знаете, что ваш `void *` указывает на какой-то объект типа `float`, то доступиться к этому объекту типа `float` вы сможете только после приведения `void *` к типу `float *`.
OK, в каком месте вышеуказанного кода мы приводим `void *` к типу `float *` ?
Сказано же "доступиться к этому объекту типа `float` вы сможете только после приведения `void *` к типу `float *`". Ключевое слово - доступиться. В вашем вышеуказанном коде никаких попыток доступится к объекту типа `float` нет и в помине. В тексте вы у себя упоминаете доступ (цитирую: "...чтобы в какой-то момент изменить значение данной переменной по данному адресу..."), а в коде - ни разу даже и не пытались. Поэтому и приведения в вашем коде нет.
Best regards,
Андрей
User avatar
AndreyT
Уже с Приветом
Posts: 3000
Joined: 14 Apr 2004 01:11
Location: SFBA (было: Минск, Беларусь)

Re: void pointer

Post by AndreyT »

AndreyT wrote:
thinker wrote:
AndreyT wrote:Если вы лично знаете, что ваш `void *` указывает на какой-то объект типа `float`, то доступиться к этому объекту типа `float` вы сможете только после приведения `void *` к типу `float *`.
OK, в каком месте вышеуказанного кода мы приводим `void *` к типу `float *` ?
Сказано же "доступиться к этому объекту типа `float` вы сможете только после приведения `void *` к типу `float *`". Ключевое слово - доступиться. В вашем вышеуказанном коде никаких попыток доступится к объекту типа `float` нет и в помине. В тексте вы у себя упоминаете доступ (цитирую: "...чтобы в какой-то момент изменить значение данной переменной по данному адресу..."), а в коде - ни разу даже и не пытались. Поэтому и приведения нет.
Best regards,
Андрей
User avatar
thinker
Уже с Приветом
Posts: 26871
Joined: 29 Aug 2000 09:01

Re: void pointer

Post by thinker »

То есть вы считаете, что поинтер в вышеуказанном коде не будет работать правильно? Тогда приведите как это исправить так чтобы мы могли обращаться к переменной fnum через поинтер void *ptr.
All rights reserved, all wrongs revenged.
User avatar
AndreyT
Уже с Приветом
Posts: 3000
Joined: 14 Apr 2004 01:11
Location: SFBA (было: Минск, Беларусь)

Re: void pointer

Post by AndreyT »

thinker wrote:То есть вы считаете, что поинтер в вышеуказанном коде не будет работать правильно? Тогда приведите как это исправить так чтобы мы могли обращаться к переменной fnum через поинтер void *ptr.
Мы, очевидно, друг друга не понимаем. Все будет правильно работать. Только для того, чтобы, например, прочитать значение вашей переменной

Code: Select all

float fnum = 42;
через указатель

Code: Select all

void *ptr = &fnum;
вам придется поступить так

Code: Select all

float value = *(float *) ptr;
Т.е. вам придется выполнить преобразование типа от `void *` к `float *`. Результат этого преобразования типа - это уже новый самостоятельный временный указатель типа `float *`. Вот через него вы в данном примере и работаете.

Всякий раз, когда вы захотите доступиться к вашей `float` переменной через `ptr`, по чтению ли, по записи ли, вам волей-неволей придется выполнять преобразование типа к `float *`.
Best regards,
Андрей
User avatar
thinker
Уже с Приветом
Posts: 26871
Joined: 29 Aug 2000 09:01

Re: void pointer

Post by thinker »

называется type-casting. Понял, спасибо.
All rights reserved, all wrongs revenged.
User avatar
АццкоМото
Уже с Приветом
Posts: 15276
Joined: 01 Mar 2007 05:18
Location: VVO->ORD->DFW->SFO->DFW->PDX

Re: void pointer

Post by АццкоМото »

OtherSide wrote:Секундочку.. Вообще-то ведь нельзя указатель на Void создать. Как можно создать указатель на участок памяти размерностью 0
например, так:

Code: Select all

 void* ass = (void *) "жопа";
Мат на форуме запрещен, блдж!
User avatar
АццкоМото
Уже с Приветом
Posts: 15276
Joined: 01 Mar 2007 05:18
Location: VVO->ORD->DFW->SFO->DFW->PDX

Re: void pointer

Post by АццкоМото »

thinker wrote:
OtherSide wrote:Секундочку.. Вообще-то ведь нельзя указатель на Void создать. Как можно создать указатель на участок памяти размерностью 0
размерность будет не ноль а такая, на которую указывает void pointer.
размерности как таковой может не быть
дорожный знак "до чикаго 123 мили" ничего не говорит о протяженности чикаго.
впрочем, АндрейТ как всегда все качественно абиснил
Мат на форуме запрещен, блдж!
User avatar
thinker
Уже с Приветом
Posts: 26871
Joined: 29 Aug 2000 09:01

Re: void pointer

Post by thinker »

AndreyT wrote:Т.е. вам придется выполнить преобразование типа от `void *` к `float *`. Результат этого преобразования типа - это уже новый самостоятельный временный указатель типа `float *`.
Кстати при передачи void pointer'a в другую функцию, например:

Code: Select all

void qsort(void *base, size_t nmemb, size_t size,  int(*compar)(const void *, const void *));
...
...
qsort( array, 10 , sizeof( int ), int_sorter );
где происходит преобразование такого поинтера в конкретный тип данных? Меня интересует поинтер void *base. Ведь при передаче массива "array" функция qsort не знает тип переданных ей данных.
All rights reserved, all wrongs revenged.
User avatar
AndreyT
Уже с Приветом
Posts: 3000
Joined: 14 Apr 2004 01:11
Location: SFBA (было: Минск, Беларусь)

Re: void pointer

Post by AndreyT »

thinker wrote:Кстати при передачи void pointer'a в другую функцию, например:

Code: Select all

void qsort(void *base, size_t nmemb, size_t size,  int(*compar)(const void *, const void *));
...
...
qsort( array, 10 , sizeof( int ), int_sorter );
где происходит преобразование такого поинтера в конкретный тип данных? Меня интересует поинтер void *base. Ведь при передаче массива "array" функция qsort не знает тип переданных ей данных.
А функция `qsort`, как таковая, и не хочет его знать. Внутри функции `qsort` работа ведется в терминах байтов, поэтому сама функция `qsort` будет приводить все указатели к типу `char *` и выполнять адресную арифметику в терминах типа `char *`. Всё, что `qsort` хочет дополнительно знать про ваши данные, это их количество - параметр `nmemb` - и размер индивидуального элемента в байтах - параметр `size`. Эти размеры будут использоваться `qsort` для выполнения адресной арифметики над `(char *) base`. Т.е. `(char *) base + i * size` даёт указатель на положение в памяти i-того элемента вашего массива. Это всё, что нужно самой `qsort`.

К вашим конкретным данным реализация функции `qsort` сама по себе никогда не доступается - сами данные голому алгоритму `qsort` глубоко безразличны. И конкретный тип ваших данных функции `qsort` тоже глубоко безразличен. Функцию `qsort` интересует только положение элементов вашего массива (см. выше) и результат сравнения элементов вашего массива. А сравнение будет выполнять отнюдь не сам `qsort`. Сравнение будете выполнять вы сами. Вы сами предоставляете `qsort` вашу собственную callback-функцию `int_sorter` для сравнения элементов вашего массива. Вы сами, разумеется, знаете, что ваш массив содержит элементы типа `int`. Поэтому внутри вашей `int_sorter` вы сами будете приводить переданные вам из `qsort` указатели типа `const void *` к типу `const int *` и выполнять сравнение. Например, для сортировки целых чисел по возрастанию

Code: Select all

int int_sorter(const void *p1, const void *p2)
{
  const int *i1 = p1, *i2 = p2;
  return (*i1 > *i2) - (*i1 < *i2);
}
Вот оно, то самое приведение типа, о котором вы спрашивали. Еще раз, заметьте, что приведение типа расположено в вашем коде, а не в коде `qsort`.

Этот callback-компаратор - это единственное место во всей процедуре сортировки, которое работает с вашим конктерным типом `int`. Самой же общей реализации `qsort`, как я уже говорил выше, до вашего конкретного типа данных никакого дела нет. `qsort` хочет знать лишь размер ваших данных и вы этот размер туда сами передаете.
Best regards,
Андрей
User avatar
AndreyT
Уже с Приветом
Posts: 3000
Joined: 14 Apr 2004 01:11
Location: SFBA (было: Минск, Беларусь)

Re: void pointer

Post by AndreyT »

AndreyT wrote:
thinker wrote:Кстати при передачи void pointer'a в другую функцию, например:

Code: Select all

void qsort(void *base, size_t nmemb, size_t size,  int(*compar)(const void *, const void *));
...
...
qsort( array, 10 , sizeof( int ), int_sorter );
где происходит преобразование такого поинтера в конкретный тип данных? Меня интересует поинтер void *base. Ведь при передаче массива "array" функция qsort не знает тип переданных ей данных.
А функция `qsort`, как таковая, и не хочет его знать. Внутри функции `qsort` работа ведется в терминах байтов, поэтому сама функция `qsort` будет приводить все указатели к типу `char *` и выполнять адресную арифметику в терминах типа `char *`. Всё, что `qsort` хочет дополнительно знать про ваши данные, это их количество - параметр `nmemb` - и размер индивидуального элемента в байтах - параметр `size`. Эти размеры будут использоваться `qsort` для выполнения адресной арифметики над `(char *) base`. Т.е. `(char *) base + i * size` даёт указатель на i-тый элемент вашего массива. Это всё что нужно самой `qsort`.

К вашим конкретным данным реализация функции `qsort` сама по себе никогда не доступается - сами данные голому алгоритму `qsort` глубоко безразличны. И конкретный тип ваших данных функции `qsort` тоже глубоко безразличен. Функцию `qsort` интересует только результат сравнения элементов вашего массива. А сравнение будет выполнять отнюдь не сам `qsort`. Сравнение будете выполнять вы сами. Вы сами предоставляете `qsort` вашу собственную callback-функцию `int_sorter` для сравнения элементов вашего массива. Вы сами, разумеется, знаете, что ваш массив содержит элементы типа `int`. Поэтому внутри вашей `int_sorter` вы сами будете приводить переданные вам из `qsort` указатели типа `const void *` к типу `const int *` и выполнять сравнение. Например, для сортировки целых чисел по возрастанию

Code: Select all

int int_sorter(const void *p1, const void *p2)
{
  const int *i1 = p1, *i2 = p2;
  return (*i1 > *i2) - (*i1 < *i2);
}
Вот оно, то самое приведение типа, о котором вы спрашивали. Еще раз, заметьте, что приведение типа расположено в вашем коде, а не в коде `qsort`.

Этот callback-компаратор - это единственное место во всей процедуре сортировки, которое работает с вашим конктерным типом `int`. Самой же общей реализации `qsort`, как я уже говорил выше, до вашего конкретного типа данных никакого дела нет. `qsort` хочет знать лишь размер ваших данных и вы этот размер туда сами передаете.
Best regards,
Андрей

Return to “Вопросы и новости IT”