studio programacion para móviles español edición desarrollo desarrollar curso aprende aplicaciones c pointers casting

programacion - Lanzar un puntero: ¿cuál es la diferencia en el tiempo de ejecución?



manual programacion android español pdf (6)

Considere el siguiente pequeño código de ejemplo:

#include <stdio.h> #include <stdlib.h> int main() { int *i; char *c1, *c2; i = malloc(4); *i = 65535; c1 = i; c2 = (char *)i; printf("%p %p %p/n", i, c1, c2); printf("%d %d", *c1, *c2); free(i); return 0; }

En el ejemplo, asigno memoria para almacenar un número entero, que es señalado por i . Luego, almaceno el valor 65535 (1111 1111 1111 1111) en *i . Lo siguiente que hago es hacer que dos punteros char * también apunten al entero. Lo hago dos veces, pero de dos maneras diferentes: c1 = i; y c2 = (char *)i; . Finalmente, imprimo todos los punteros y todos los valores en la pantalla. Los tres punteros apuntan a la misma dirección, y los dos valores *c1 y *c2 son correctos (-1) .

Sin embargo, el compilador genera una advertencia en esta línea: c1 = i; . La advertencia se genera porque no usé la (char *) para realizar la tarea.

Lo que me gustaría preguntar es por qué el compilador genera esta advertencia, ya que no veo ninguna diferencia en el uso de c1 = i ; o c2 = (char *)i; . En ambos casos, el resultado es la misma dirección con el mismo tamaño en bytes. Y esto es válido para todos los cast, incluso si es un cast (int *) , (float *) cast, (short *) cast, etc. Todos ellos generan el mismo valor, pero el compilador solo lo aceptará sin una advertencia si el modelo utilizado es el tipo de puntero.

Realmente me gustaría saber por qué el compilador solicita ese reparto, incluso si el resultado es siempre el mismo.


Cuando usas:

c2 = i;

el compilador le advierte sobre la asignación del tipo int* a char* . Potencialmente podría ser un error involuntario. El compilador le advierte con la esperanza de que, si se trata de un error involuntario, tenga la oportunidad de solucionarlo.

Cuando usas:

c2 = (char *)i;

Le está diciendo al compilador que usted, como programador, sabe lo que está haciendo.


Desafortunadamente la mejor respuesta está en los comentarios a la pregunta!

Ver el comentario de @PieterWitvoet:

En C, el sistema de tipo es una ''herramienta'' de tiempo de compilación que le impide realizar operaciones no válidas. Las cosas de diferentes tipos tienen diferentes operaciones disponibles para ellos, y el compilador se está asegurando de que solo esté usando operaciones válidas. Pero algunas operaciones destinadas a un tipo pueden funcionar bien para otro tipo, así que cuando quiera usarlas, puede realizar una conversión de tipos, que básicamente le dice al compilador: "Sé lo que estoy haciendo, solo finja que Aquí es del tipo que es válido para esta operación ".

En caso de que aún no entienda el punto: C es un lenguaje tipado estáticamente. Lo que esto significa es que el programador debe definir el tipo de identificadores antes de usarlos. Por lo tanto, uno de los propósitos de un compilador de C es asegurar que usted haya asignado un tipo a todos los identificadores. Otro propósito sería asegurar que los valores asignados sean del mismo tipo que el del identificador al que se asignan. En el caso de los punteros, son internamente del mismo tipo, es decir, son de 32 bits en sistemas de 32 bits. Sin embargo, el aspecto de alto nivel de los punteros es que son punteros a un cierto "tipo" de datos. Como tal, tiene sentido asegurar que a un puntero se le asigne una dirección de datos que sea del tipo esperado. Recuerdo vagamente que esa comprobación no existió originalmente y se agregó en una versión posterior del estándar C. Sin embargo, podría estar equivocado. Si tal comprobación no está en su lugar, entonces uno podría terminar almacenando la dirección de datos incorrectos y esto se materializaría como un error de tiempo de ejecución. Por ejemplo, asignando la dirección de una estructura a un int / char / cualquier otro tipo y luego indireccionando a la misma asumiendo que es del tipo de estructura en cuestión podría dar lugar a problemas inesperados en el tiempo de ejecución. No es que tales asignaciones no sean válidas, como tal, el compilador le avisa y si escribe el valor de conversión, entonces el compilador no se preocupará por eso, ya que entiende que usted sabe lo que está haciendo.


El compilador solo conoce la conversión de un puntero genérico void * a cualquier puntero y viceversa implícitamente. Aparte del puntero genérico, se espera que una conversión antes de la asignación del puntero haga punteros de tipo compatible y decida que la asignación se realice a sabiendas.


En soluciones más complejas puede haber problemas si no lo haces. No causa problemas en este caso, pero cuando el compilador necesita tratar la ubicación de memoria apuntada por su tipo, puede tratarlo mal. Tenga en cuenta que char tiene una longitud de 1 byte, mientras que int tiene una longitud de 4 u 8 bytes.


Los punteros a objetos de diferentes tipos pueden diferir en su respectivo tamaño y alineación:

§6.2.5 / 26 tipos

Un puntero para anular tendrá los mismos requisitos de representación y alineación que un puntero a un tipo de carácter. De manera similar, los punteros a versiones calificadas o no calificadas de tipos compatibles deben tener los mismos requisitos de representación y alineación. Todos los punteros a los tipos de estructura deben tener los mismos requisitos de representación y alineación que los demás. Todos los punteros a los tipos de unión deben tener los mismos requisitos de representación y alineación que los demás. Los punteros a otros tipos no necesitan tener los mismos requisitos de representación o alineación.

Especialmente, sizeof(char *) puede tener un valor diferente que sizeof(int *) . Además, char * puede tener diferentes requisitos de alineación que int * . Por lo tanto, el elenco implícito produce una advertencia. Es por eso que el estándar C contiene la siguiente guía:

§6.5.4 / 1

Las conversiones que involucran punteros, aparte de lo permitido por las restricciones de 6.5.16.1, se especificarán por medio de una conversión explícita.


Su programa no es válido; la asignación entre tipos de punteros no está permitida cuando los tipos apuntados son tipos incompatibles, a menos que se utilice una conversión.

6.5.4 Operadores de fundición

3 - Las conversiones que involucran punteros, que no sean las permitidas por las restricciones de 6.5.16.1, se especificarán por medio de una conversión explícita.

El compilador está aceptando su código como una extensión , pero otro compilador podría rechazar su código y sería correcto hacerlo. Es por esto que el compilador está emitiendo una advertencia cuando omite la conversión.