¿Es posible desreferenciar un puntero vacío sin conversión de tipos en el lenguaje de programación C?
Además, ¿hay alguna forma de generalizar una función que pueda recibir un puntero y almacenarlo en un puntero vacío y, al usar ese puntero vacío, podemos hacer una función generalizada?
por ejemplo:
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
}
Quiero hacer que esta función sea genérica sin usar sentencias if-else: ¿es esto posible?
Además, si hay buenos artículos en Internet que explican el concepto de un puntero nulo, sería beneficioso si pudiera proporcionar las URL.
Además, ¿es posible la aritmética de puntero con punteros vacíos?
fuente
void *
punteros de la misma manera quechar *
, pero no es estándar y no debes confiar en ella.En C, a
void *
se puede convertir en un puntero a un objeto de un tipo diferente sin una conversión explícita:Sin embargo, esto no ayuda a escribir su función de una manera más genérica.
No puede desreferenciar a
void *
con convertirlo a un tipo de puntero diferente ya que al desreferenciar un puntero se obtiene el valor del objeto señalado. Un desnudovoid
no es un tipo válido, porvoid *
lo que no es posible desreferenciarlo .La aritmética del puntero se trata de cambiar los valores del puntero por múltiplos de los
sizeof
objetos apuntados. Nuevamente, debido avoid
que no es un tipo verdadero,sizeof(void)
no tiene significado, por lo que la aritmética del puntero no es válidavoid *
. (Algunas implementaciones lo permiten, utilizando la aritmética de puntero equivalente parachar *
).fuente
void abc(void *a, int b)
. Pero por qué no usarlovoid abc(int *a, int b)
, ya que en su función eventualmente definiráint *test = a;
, guardaría una variable, y no veo ninguna otra ventaja al definir otra variable. Veo muchos códigos escritos de esta manera usandovoid *
como parámetros y enviando variables más adelante en la función. Pero dado que esta función está escrita por el autor, debe saber el uso de la variable, por lo tanto, ¿por qué usarlavoid *
? GraciasDebe tener en cuenta que en C, a diferencia de Java o C #, no hay absolutamente ninguna posibilidad de "adivinar" con éxito el tipo de objeto al que
void*
apunta un puntero. Algo similar agetClass()
simplemente no existe, ya que esta información no se encuentra en ninguna parte. Por esa razón, el tipo de "genérico" que busca siempre viene con metainformación explícita, comoint b
en su ejemplo o la cadena de formato en laprintf
familia de funciones.fuente
Un puntero vacío se conoce como puntero genérico, que puede referirse a variables de cualquier tipo de datos.
fuente
Hasta ahora, mi comprensión del puntero vacío es la siguiente.
Cuando se declara una variable de puntero utilizando la palabra clave void, se convierte en una variable de puntero de uso general. La dirección de cualquier variable de cualquier tipo de datos (char, int, float, etc.) se puede asignar a una variable de puntero vacío.
Dado que se puede asignar otro puntero de tipo de datos al puntero vacío, entonces lo usé en la función absolut_value (el código se muestra a continuación). Para hacer una función general.
Traté de escribir un código C simple que toma un entero o flotante como argumento y trata de hacerlo + ve, si es negativo. Escribí el siguiente código,
Pero recibía un error, así que llegué a saber que mi comprensión con el puntero de vacío no es correcta :(. Así que ahora me moveré hacia la recopilación de puntos, ¿por qué es así?
Lo que necesito entender más sobre los punteros nulos es eso.
Necesitamos encasillar la variable de puntero vacío para desreferenciarla. Esto se debe a que un puntero vacío no tiene ningún tipo de datos asociado. No hay forma de que el compilador pueda saber (¿o adivinar?) A qué tipo de datos apunta el puntero vacío. Por lo tanto, para tomar los datos señalados por un puntero vacío, los encasillamos con el tipo correcto de datos retenidos dentro de la ubicación de los punteros vacíos.
Un puntero nulo puede ser realmente útil si el programador no está seguro sobre el tipo de datos ingresados por el usuario final. En tal caso, el programador puede usar un puntero vacío para apuntar a la ubicación del tipo de datos desconocido. El programa se puede configurar de tal manera que solicite al usuario que informe el tipo de datos y la conversión de tipos se puede realizar de acuerdo con la información ingresada por el usuario. A continuación se incluye un fragmento de código.
Otro punto importante que debe tener en cuenta sobre los punteros vacíos es que: la aritmética del puntero no se puede realizar en un puntero vacío.
Así que ahora entendí cuál fue mi error. Estoy corrigiendo lo mismo.
Referencias
http://www.antoarts.com/void-pointers-in-c/
http://www.circuitstoday.com/void-pointers-in-c .
El nuevo código es como se muestra a continuación.
Gracias,
fuente
No, no es posible. ¿Qué tipo debe tener el valor desreferenciado?
fuente
fuente
printf
. Esta respuesta tiene un buen ejemplo para eso.int b
con una enumeración, pero hacer cualquier cambio posterior a esa enumeración rompería esta función.La única forma simple que veo es utilizar la sobrecarga ... que no está disponible en el lenguaje de programación C AFAIK.
¿Consideró el lenguaje de programación C ++ para su programa? ¿O hay alguna restricción que prohíba su uso?
fuente
Aquí hay un breve puntero sobre
void
punteros: https://www.learncpp.com/cpp-tutorial/613-void-pointers/Suponiendo que la memoria de la máquina es direccionable por bytes y no requiere accesos alineados, la forma más genérica y atómica (más cercana a la representación a nivel de máquina) de interpretar a
void*
es como un puntero a un byteuint8_t*
. Lanzar unvoid*
a auint8_t*
le permitiría, por ejemplo, imprimir los primeros 1/2/4/8 / sin embargo, muchos bytes que desee a partir de esa dirección, pero no puede hacer mucho más.fuente
Puede imprimir fácilmente una impresora vacía
fuente
void
tiene el mismo tamaño queint
?void
puntero, está imprimiendoint
en la dirección de memoria que contiene el puntero (que en este caso sería el valor dep
).Debido a que C es un lenguaje fuertemente tipado estáticamente, debe decidir el tipo de variable antes de compilar. Cuando intentes emular genéricos en C, terminarás intentando reescribir C ++ nuevamente, por lo que sería mejor usar C ++ en su lugar.
fuente
El puntero vacío es un puntero genérico. La dirección de cualquier tipo de datos de cualquier variable puede asignarse a un puntero vacío.
fuente
No puede desreferenciar un puntero sin especificar su tipo porque los diferentes tipos de datos tendrán diferentes tamaños en la memoria, es decir, un int es de 4 bytes, un char es de 1 byte.
fuente
Básicamente, en C, los "tipos" son una forma de interpretar los bytes en la memoria. Por ejemplo, cuál es el siguiente código
Dice "Cuando ejecuto main, quiero asignar 4 (tamaño de entero) + 4 (tamaño de entero) = 8 (bytes totales) de memoria. Cuando escribo '.x' como valor de l en un valor con la etiqueta de tipo Apunte al tiempo de compilación, recupere datos de la ubicación de la memoria del puntero más cuatro bytes. Dé al valor de retorno la etiqueta de tiempo de compilación "int".
Dentro de la computadora en tiempo de ejecución, su estructura de "Punto" se ve así:
Y así es
void*
como se vería su tipo de datos: (suponiendo que una computadora de 32 bits)fuente
Esto no funcionará, pero void * puede ayudar mucho a definir el puntero genérico a las funciones y pasarlo como argumento a otra función (similar a la devolución de llamada en Java) o definirlo como una estructura similar a oop.
fuente