Сегодня, когда я читал чужой код, я увидел что-то вроде void *func(void* i);: что это void*значит здесь для имени функции и типа переменной соответственно?
Кроме того, когда нам нужно использовать указатель такого типа и как его использовать?
Возьмите реплику с mallocи calloc. Страница man продолжает: «... возвращает указатель на выделенную память, которая соответствующим образом выровнена для любого встроенного типа данных».
автомат
Ответы:
175
Указатель на voidэто «универсальный» тип указателя. A void *может быть преобразован в любой другой тип указателя без явного приведения. Вы не можете разыменовывать void *или делать арифметику указателей с ним; Вы должны сначала преобразовать его в указатель на полный тип данных.
void *часто используется в местах, где вам нужно иметь возможность работать с разными типами указателей в одном и том же коде. Одним из часто цитируемых примеров является функция библиотеки qsort:
baseэто адрес массива, nmembэто количество элементов в массиве, sizeэто размер каждого элемента, иcompar является указателем на функцию, которая сравнивает два элемента массива. Это называется так:
Выражения массива iArr, dArrи lArrнеявно преобразуется из типов массивов для типов указателей в вызове функции, и каждый неявно преобразуются из «указателя int/double / long» в «указатель void».
Функции сравнения будут выглядеть примерно так:
int compareInt(constvoid*lhs,constvoid*rhs){constint*x = lhs;// convert void * to int * by assignmentconstint*y = rhs;if(*x >*y)return1;if(*x ==*y)return0;return-1;}
Принимая void * , qsortможно работать с массивами любого типа.
Недостаток использования void * заключается в том, что вы выбрасываете безопасность типов в окно и во встречный трафик. Там нет ничего, чтобы защитить вас от использования неправильной процедуры сравнения:
compareIntожидает, что его аргументы будут указывать на ints, но на самом деле работает с doubles. Нет способа поймать эту проблему во время компиляции; вы просто получите пропущенный массив.
На самом деле не гарантируется, что a void*может быть приведен к указателю на функцию. Но для указателей данных то, что вы сказали, имеет место.
Ватин
До того, как указатели на void стали доступны, вместо них использовался «char *». Но пустота лучше, поскольку она не может быть использована для непосредственного изменения чего-либо.
user50619
22
Использование void * означает, что функция может получить указатель, который не должен быть определенного типа. Например, в функциях сокетов у вас есть
send(void* pData,int nLength)
это означает, что вы можете назвать это разными способами, например
char* data ="blah";
send(data, strlen(data));
POINT p;
p.x =1;
p.y =2;
send(&p,sizeof(POINT));
Так что это почти как дженерики в других языках, но без проверки типов, верно?
Вингер Сендон
3
Я полагаю, что это будет похоже, однако, поскольку нет проверки типов, ошибка может привести к очень странным результатам или вызвать полный сбой программы.
TheSteve
7
С примечателен в этом отношении. Можно сказать, voidчто ничто void*есть все (может быть все).
Это просто крошечный, *который имеет значение.
Рене указал на это. void *Является указателем на какое - то место. То, что есть как «интерпретировать», остается за пользователем.
Это единственный способ иметь непрозрачные типы в C. Очень выдающиеся примеры можно найти, например, в библиотеках glib или общих структурах данных. Об этом очень подробно говорится в разделе «Интерфейсы и реализации C».
Я предлагаю вам прочитать всю главу и попытаться понять концепцию указателя, чтобы «получить его».
является «указателем на память без предположений, какой тип там хранится». Вы можете использовать, например, если вы хотите передать аргумент функции, и этот аргумент может быть нескольких типов, и в функции вы будете обрабатывать каждый тип.
Указатель типа void - это специальный тип указателя. В C ++ void представляет отсутствие типа, поэтому указатели void - это указатели, которые указывают на значение, которое не имеет типа (и, следовательно, также имеет неопределенную длину и неопределенные свойства разыменования).
Это позволяет указателям void указывать на любой тип данных, от целочисленного значения или с плавающей точкой до строки символов. Но взамен они имеют большое ограничение: данные, на которые они указывают, не могут быть напрямую разыменованы (что логично, поскольку у нас нет типа для разыменования), и по этой причине нам всегда придется приводить адрес в пустом указателе на некоторый другой тип указателя, который указывает на конкретный тип данных перед разыменованием его.
Пустой указатель известен как универсальный указатель. Я хотел бы объяснить с примером сценария pthread.
Функция потока будет иметь прототип как
void*(*start_routine)(void*)
Разработчики API pthread рассмотрели аргумент и возвращаемые значения функции потока. Если эти вещи сделаны общими, мы можем напечатать cast to void * при отправке в качестве аргумента. аналогично, возвращаемое значение может быть получено из void * (но я никогда не использовал возвращаемые значения из функции потока).
void*PrintHello(void*threadid){long tid;// ***Arg sent in main is retrieved ***
tid =(long)threadid;
printf("Hello World! It's me, thread #%ld!\n", tid);
pthread_exit(NULL);}int main (int argc,char*argv[]){pthread_t threads[NUM_THREADS];int rc;long t;for(t=0; t<NUM_THREADS; t++){//*** t will be type cast to void* and send as argument.
rc = pthread_create(&threads[t], NULL,PrintHello,(void*)t);if(rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);}}/* Last thing that main() should do */
pthread_exit(NULL);}
a void*является указателем, но тип того, на что он указывает, не указан. Когда вы передаете пустой указатель на функцию, вам нужно знать, какой у нее был тип, чтобы потом привести ее к правильному типу в функции, чтобы использовать ее. В этом примере вы увидите примеры pthreadsиспользования функций с именно прототипом, которые используются в качестве функции потока. Затем вы можете использовать void*аргумент в качестве указателя на общий тип данных по вашему выбору, а затем привести его обратно к этому типу для использования в вашей функции потока. Вы должны быть осторожны при использовании указателей void, хотя, если только вы не вернетесь к указателю его истинного типа, вы можете столкнуться со всевозможными проблемами.
Указатель на voidможет быть преобразован в или из указателя на любой тип объекта. Указатель на любой тип объекта может быть преобразован в указатель на void и обратно; результат должен сравниваться равным исходному указателю.
Вы можете использовать этот универсальный указатель для хранения указателя на любой тип объекта, но вы не можете использовать обычные арифметические операции с ним и не можете его использовать.
malloc
иcalloc
. Страница man продолжает: «... возвращает указатель на выделенную память, которая соответствующим образом выровнена для любого встроенного типа данных».Ответы:
Указатель на
void
это «универсальный» тип указателя. Avoid *
может быть преобразован в любой другой тип указателя без явного приведения. Вы не можете разыменовыватьvoid *
или делать арифметику указателей с ним; Вы должны сначала преобразовать его в указатель на полный тип данных.void *
часто используется в местах, где вам нужно иметь возможность работать с разными типами указателей в одном и том же коде. Одним из часто цитируемых примеров является функция библиотекиqsort
:base
это адрес массива,nmemb
это количество элементов в массиве,size
это размер каждого элемента, иcompar
является указателем на функцию, которая сравнивает два элемента массива. Это называется так:Выражения массива
iArr
,dArr
иlArr
неявно преобразуется из типов массивов для типов указателей в вызове функции, и каждый неявно преобразуются из «указателяint
/double
/long
» в «указательvoid
».Функции сравнения будут выглядеть примерно так:
Принимая
void *
,qsort
можно работать с массивами любого типа.Недостаток использования
void *
заключается в том, что вы выбрасываете безопасность типов в окно и во встречный трафик. Там нет ничего, чтобы защитить вас от использования неправильной процедуры сравнения:compareInt
ожидает, что его аргументы будут указывать наint
s, но на самом деле работает сdouble
s. Нет способа поймать эту проблему во время компиляции; вы просто получите пропущенный массив.источник
void*
может быть приведен к указателю на функцию. Но для указателей данных то, что вы сказали, имеет место.Использование void * означает, что функция может получить указатель, который не должен быть определенного типа. Например, в функциях сокетов у вас есть
это означает, что вы можете назвать это разными способами, например
источник
С примечателен в этом отношении. Можно сказать,
void
что ничтоvoid*
есть все (может быть все).Это просто крошечный,
*
который имеет значение.Рене указал на это.
void *
Является указателем на какое - то место. То, что есть как «интерпретировать», остается за пользователем.Это единственный способ иметь непрозрачные типы в C. Очень выдающиеся примеры можно найти, например, в библиотеках glib или общих структурах данных. Об этом очень подробно говорится в разделе «Интерфейсы и реализации C».
Я предлагаю вам прочитать всю главу и попытаться понять концепцию указателя, чтобы «получить его».
источник
является «указателем на память без предположений, какой тип там хранится». Вы можете использовать, например, если вы хотите передать аргумент функции, и этот аргумент может быть нескольких типов, и в функции вы будете обрабатывать каждый тип.
источник
Вы можете взглянуть на эту статью об указателях http://www.cplusplus.com/doc/tutorial/pointers/ и прочитать главу: void pointers .
Это также работает для языка Си.
источник
Пустой указатель известен как универсальный указатель. Я хотел бы объяснить с примером сценария pthread.
Функция потока будет иметь прототип как
Разработчики API pthread рассмотрели аргумент и возвращаемые значения функции потока. Если эти вещи сделаны общими, мы можем напечатать cast to void * при отправке в качестве аргумента. аналогично, возвращаемое значение может быть получено из void * (но я никогда не использовал возвращаемые значения из функции потока).
источник
pthread_exit(NULL);
аreturn 0;
не в конце основного?a
void*
является указателем, но тип того, на что он указывает, не указан. Когда вы передаете пустой указатель на функцию, вам нужно знать, какой у нее был тип, чтобы потом привести ее к правильному типу в функции, чтобы использовать ее. В этом примере вы увидите примерыpthreads
использования функций с именно прототипом, которые используются в качестве функции потока. Затем вы можете использоватьvoid*
аргумент в качестве указателя на общий тип данных по вашему выбору, а затем привести его обратно к этому типу для использования в вашей функции потока. Вы должны быть осторожны при использовании указателей void, хотя, если только вы не вернетесь к указателю его истинного типа, вы можете столкнуться со всевозможными проблемами.источник
Стандарт C11 (n1570) §6.2.2.3 al1 p55 гласит:
Вы можете использовать этот универсальный указатель для хранения указателя на любой тип объекта, но вы не можете использовать обычные арифметические операции с ним и не можете его использовать.
источник
Функция берет указатель на произвольный тип и возвращает один такой.
источник
это означает указатель, вы можете использовать эту ссылку, чтобы получить больше информации об указателе http://www.cprogramming.com/tutorial/c/lesson6.html
источник