Концепция указателя void в программировании на языке C

Возможно ли разыменовать указатель void без использования типов на языке программирования C?

Кроме того, существует ли какой-либо способ обобщения функции, которая может получить указатель и сохранить его в указателе void, и используя этот указатель void, можем ли мы сделать обобщенную функцию?

например:

void abc(void *a, int b) { if(b==1) printf("%d",*(int*)a); // If integer pointer is received else if(b==2) printf("%c",*(char*)a); // If character pointer is received else if(b==3) printf("%f",*(float*)a); // If float pointer is received } 

Я хочу сделать эту функцию обобщенной без использования инструкций if-else – это возможно?

Также, если есть хорошие интернет-статьи, которые объясняют концепцию указателя void, тогда было бы полезно, если бы вы могли предоставить URL-адреса.

Кроме того, возможна ли арифметика указателя с указателями void?

14 Solutions collect form web for “Концепция указателя void в программировании на языке C”

Можно ли разыменовать указатель на void без использования типов в C-языке программирования …

Нет, void указывает на отсутствие типа, это не то, что вы можете разыменовать или назначить.

существует ли какой-либо способ обобщения функции, которая может получать указатель и хранить его в указателе void, и с помощью этого указателя void мы можем сделать обобщенную функцию.

Вы не можете просто разыменовать его переносимым способом, поскольку он может быть неправильно выровнен. Это может быть проблемой для некоторых архитектур, таких как ARM, где указатель на тип данных должен быть выровнен на границе размера типа данных (например, указатель на 32-битное целое должен быть выровнен на границе 4 байта, чтобы разыменоваться).

Например, чтение uint16_t из void* :

 /* may receive wrong value if ptr is not 2-byte aligned */ uint16_t value = *(uint16_t*)ptr; /* portable way of reading a little-endian value */ uint16_t value = *(uint8_t*)ptr | ((*((uint8_t*)ptr+1))< <8); 

Кроме того, возможна арифметика указателя с указателями void ...

Арифметика указателя невозможна по указателям void из-за отсутствия конкретного значения под указателем и, следовательно, размера.

 void* p = ... void *p2 = p + 1; /* what exactly is the size of void?? */ 

В C, void * может быть преобразован в указатель на объект другого типа без явного приведения:

 void abc(void *a, int b) { int *test = a; /* ... */ 

Однако это не помогает при написании вашей функции более общим образом.

Вы не можете разыменовывать void * с преобразованием его в другой тип указателя, поскольку разыменование указателя – это получение значения объекта с указателем. Голая void не является допустимым типом, поэтому разрывать void * невозможно.

Арифметика указателя заключается в изменении значений указателя на кратность sizeof объектов с заостренными объектами. Опять же, поскольку void не является истинным типом, sizeof(void) не имеет значения, поэтому арифметика указателя недействительна на void * . (Некоторые реализации позволяют это, используя эквивалентную арифметику указателя для char * .)

Вы должны знать, что в C, в отличие от Java или C #, нет абсолютно никакой возможности успешно «угадать» тип объекта, на который указывает указатель void *. Нечто похожее на «getClass ()» просто не существует, поскольку эту информацию нигде не найти. По этой причине тип «общего», который вы ищете, всегда имеет явную метаинформацию, такую ​​как «int b» в вашем примере или строку формата в семействе функций printf.

До сих пор мое занижение на указателе пустоты было следующим.

Когда переменная указателя объявляется с использованием ключевого слова void – она ​​становится переменной указателя общего назначения. Адрес любой переменной любого типа данных (char, int, float и т. Д.) Может быть назначен переменной указателя void.

 main() { int *p; void *vp; vp=p; } 

Поскольку другой указатель типа данных может быть назначен указателю void, поэтому я использовал его в функции absolut_value (код, показанный ниже). Сделать общую функцию.

Я попытался написать простой C-код, который принимает целочисленный или float как аргумент и пытается сделать его + ve, если он отрицательный. Я написал следующий код,

 #include void absolute_value ( void *j) // works if used float, obviously it must work but thats not my interest here. { if ( *j < 0 ) *j = *j * (-1); } int main() { int i = 40; float f = -40; printf("print intiger i = %d \n",i); printf("print float f = %f \n",f); absolute_value(&i); absolute_value(&f); printf("print intiger i = %d \n",i); printf("print float f = %f \n",f); return 0; } 

Но я получал ошибку, поэтому я понял, что мое понимание с указателем void неверно 🙁 Итак, теперь я перейду к сбору очков, почему так.

То, что мне нужно понять больше на указателях пустоты, это то.

Нам нужно вывести переменную указателя void, чтобы разыменовать ее. Это связано с тем, что указатель void не имеет связанного с ним типа данных. Компилятор не знает (или угадывает?), На какой тип данных указывает указатель на пустоту. Поэтому, чтобы взять данные, на которые указывает указатель на void, мы выводим его с правильным типом данных, хранящихся внутри местоположения указателей void.

 void main() { int a=10; float b=35.75; void *ptr; // Declaring a void pointer ptr=&a; // Assigning address of integer to void pointer. printf("The value of integer variable is= %d",*( (int*) ptr) );// (int*)ptr - is used for type casting. Where as *((int*)ptr) dereferences the typecasted void pointer variable. ptr=&b; // Assigning address of float to void pointer. printf("The value of float variable is= %f",*( (float*) ptr) ); } 

Указатель void может быть действительно полезен, если программист не уверен в типе данных, введенных конечным пользователем. В таком случае программист может использовать указатель void для указания местоположения неизвестного типа данных. Программа может быть настроена таким образом, чтобы попросить пользователя сообщить тип данных и тип литья может выполняться в соответствии с информацией, введенной пользователем. Ниже приведен fragment кода.

 void funct(void *a, int z) { if(z==1) printf("%d",*(int*)a); // If user inputs 1, then he means the data is an integer and type casting is done accordingly. else if(z==2) printf("%c",*(char*)a); // Typecasting for character pointer. else if(z==3) printf("%f",*(float*)a); // Typecasting for float pointer } с void funct(void *a, int z) { if(z==1) printf("%d",*(int*)a); // If user inputs 1, then he means the data is an integer and type casting is done accordingly. else if(z==2) printf("%c",*(char*)a); // Typecasting for character pointer. else if(z==3) printf("%f",*(float*)a); // Typecasting for float pointer } 

Еще один важный момент, который вы должны учитывать в указателях void, состоит в том, что - арифметика указателя не может быть выполнена в указателе void.

 void *ptr; int a; ptr=&a; ptr++; // This statement is invalid and will result in an error because 'ptr' is a void pointer variable. 

Итак, теперь я понял, в чем была моя ошибка. Я исправляю то же самое.

Рекомендации :

http://www.antoarts.com/void-pointers-in-c/

http://www.circuitstoday.com/void-pointers-in-c .

Новый код показан ниже.


 #include #define INT 1 #define FLOAT 2 void absolute_value ( void *j, int *n) { if ( *n == INT) { if ( *((int*)j) < 0 ) *((int*)j) = *((int*)j) * (-1); } if ( *n == FLOAT ) { if ( *((float*)j) < 0 ) *((float*)j) = *((float*)j) * (-1); } } int main() { int i = 0,n=0; float f = 0; printf("Press 1 to enter integer or 2 got float then enter the value to get absolute value\n"); scanf("%d",&n); printf("\n"); if( n == 1) { scanf("%d",&i); printf("value entered before absolute function exec = %d \n",i); absolute_value(&i,&n); printf("value entered after absolute function exec = %d \n",i); } if( n == 2) { scanf("%f",&f); printf("value entered before absolute function exec = %f \n",f); absolute_value(&f,&n); printf("value entered after absolute function exec = %f \n",f); } else printf("unknown entry try again\n"); return 0; } 

Спасибо,

Указатель void известен как общий указатель, который может ссылаться на переменные любого типа данных.

Указатель void в c известен как общий указатель . Буквальное значение общего указателя – это указатель, который может указывать на любой тип данных .

void *ptr;

  1. Мы не можем разыменовать общий указатель на любой другой указатель.

  2. Мы можем найти размер общего указателя с помощью оператора sizeof.

  3. Общий указатель может содержать любые указатели, такие как указатель на указатель, указатель структуры, массив указателя и т. Д. Без какого-либо приведения типов.

  4. Любой тип указателя может содержать общий указатель без какого-либо приведения типов.

  5. Общие указатели используются, когда мы хотим вернуть такой указатель, который применим ко всем типам указателей. Например, возвращаемый тип функции malloc является общим указателем, поскольку он может динамически распределять пространство памяти для хранения целого числа, float, структуры и т. Д., Поэтому мы вводим тип возвращаемого типа в соответствующий тип указателя.

 void abc(void *a, int b) { char *format[] = {"%d", "%c", "%f"}; printf(format[b-1], a); } 

Что такое указатель void в c?

Указатель void в c называется общим указателем, у него нет связанного типа данных. Он может хранить адрес любого типа объекта, и он может быть отнесен к типу любого типа. Согласно стандарту C указатель на void должен иметь те же требования к представлению и выравниванию, что и указатель на тип символа. Объявление указателя void похоже на обычный указатель, но разница в том, что вместо типов данных мы используем ключевое слово void ,

Синтаксис:

 void * Pointer_Name; void *pvHandle; 

Выделение указателя пустоты в C

Используя оператор косвенности (*), мы можем вернуть значение, указанное указателем, но в случае указателя void мы не можем напрямую использовать оператор косвенности. Это связано с тем, что указатель void не имеет типа данных, что создает проблему для компилятора для outlookирования размера заостренного объекта. Поэтому, прежде чем разыгрывать void *, мы должны набирать листинг, он позволяет компилятору предсказать типы данных.

Давайте посмотрим пример кода.

 #include  #include  int main(int argc, char *argv[]) { void *pvData; int iData = 10; pvData = &iData; printf("*pvData = %d",*pvData); return 0; } 

Объяснение: Когда мы скомпилируем вышеуказанный код, мы получим ошибку компилятора, потому что в приведенном выше коде я попытался разыменовать указатель void без оболочки типа.

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

 #include  #include  int main(int argc, char *argv[]) { void *pvData; int iData = 10; pvData = &iData; printf("iData = %d",*(int*)pvData); return 0; } 

Почему используются указатели void?

Очень важной особенностью указателя void является многократное использование. Используя указатель void, мы можем сохранить адрес любого объекта, и, когда это необходимо, мы можем вернуть объект через оператор косвенности при правильной кастинге.

Согласно c стандартная арифметическая операция над указателями void является незаконной, что означает, что стандарт C не позволяет арифметику указателя с указателями void. Однако в GNU C операции сложения и вычитания поддерживаются на указателях void, предполагая, что размер void равен 1.

Рекомендации:

https://aticleworld.com/void-pointer-in-c/

https://aticleworld.com/dangling-void-null-wild-pointers/

Нет, это невозможно. Какой тип должен иметь разыменованное значение?

Я хочу сделать эту функцию общей, без использования ifs; Является ли это возможным?

Единственный простой способ, который я вижу, – это использовать перегрузку, которая недоступна в C-программировании langage AFAIK.

Вы рассматривали язык программирования C ++ для своей программы? Или существует какое-либо ограничение, запрещающее его использование?

Поскольку C является статически типизированным, строго типизированным языком, вы должны решить тип переменной перед компиляцией. Когда вы пытаетесь эмулировать дженерики в C, вы в конечном итоге попытаетесь перезаписать C ++ снова, поэтому было бы лучше использовать C ++.

Вы можете легко распечатать пустотный принтер

 int p=15; void *q; q=&p; printf("%d",*((int*)q)); 

void pointer – общий указатель. Адрес любого типа данных любой переменной может быть назначен указателю на пустоту.

 int a = 10; float b = 3.14; void *ptr; ptr = &a; printf( "data is %d " , *((int *)ptr)); //(int *)ptr used for typecasting dereferencing as int ptr = &b; printf( "data is %f " , *((float *)ptr)); //(float *)ptr used for typecasting dereferencing as float 

Это не сработает, но void * может помочь в определении общего указателя на функции и передачи его в качестве аргумента другой функции (аналогичной обратному вызову в Java) или определить ее структуру, похожую на oop.

Давайте будем гением компьютера.