static_cast sirve que pointer para dynamic_cast array c pointers casting initialization assignment-operator

sirve - return pointer c



Problemas de "puntero de entero/entero de puntero sin conversión" (1)

No, no es válido C y nunca ha sido válido C. Estos ejemplos se denominan supuestas violaciones de la norma.

El estándar no le permite inicializar / asignar un puntero a un entero, ni un entero a un puntero. Es necesario forzar manualmente una conversión de tipo con un lanzamiento:

int* p = (int*) 0x1234; int i = (int)p;

Si no usa la conversión, el código no es válido en C y su compilador no puede permitir que el código pase sin mostrar un mensaje. Específicamente, esto está regulado por las reglas de asignación simple , C17 6.5.16.1 §1:

6.5.16.1 Asignación simple

Restricciones

Se mantendrá uno de los siguientes:

  • el operando izquierdo tiene un tipo aritmético atómico, calificado o no calificado, y el derecho tiene un tipo aritmético;
  • el operando de la izquierda tiene una versión atómica, calificada o no calificada de una estructura o tipo de unión compatible con el tipo de la derecha;
  • el operando de la izquierda tiene un tipo de puntero atómico, calificado o no calificado, y (considerando el tipo que tendría el operando de la izquierda después de la conversión del valor), ambos operandos son punteros a versiones calificadas o no calificadas de los tipos compatibles, y el tipo señalado por la izquierda tiene todos los calificadores del tipo señalado por el derecho;
  • el operando de la izquierda tiene un tipo de puntero atómico, calificado o no calificado y (considerando el tipo que tendría el operando de la izquierda después de la conversión de valores) un operando es un puntero a un tipo de objeto, y el otro es un puntero a una versión calificada o no calificada de nulo, y el tipo apuntado por la izquierda tiene todos los calificadores del tipo apuntado por la derecha;
  • El operando izquierdo es un puntero atómico, calificado o no calificado, y el derecho es una constante de puntero nulo; o
  • El operando de la izquierda tiene un tipo atómico, calificado o no calificado _Bool, y la derecha es un puntero.

En el caso de int* p = 0x12345678; , el operando izquierdo es un puntero y el derecho es un tipo aritmético.
En caso de int i = p; , el operando izquierdo es un tipo aritmético y el derecho es un puntero.
Ninguno de estos encaja con ninguna de las restricciones citadas anteriormente.

En cuanto a por qué int* p = 0; Funciona, es un caso especial. El operando izquierdo es un puntero y el derecho es una constante de puntero nulo . Más información sobre la diferencia entre los punteros nulos, las constantes de puntero nulo y la macro NULL .

Algunas cosas de la nota:

  • Si asigna una dirección en bruto a un puntero, es probable que el puntero tenga que ser calificado volatile , dado que apunta a algo como un registro de hardware o una ubicación EEPROM / memoria Flash, que puede cambiar su contenido en tiempo de ejecución.

  • La conversión de un puntero a un número entero no garantiza de ninguna manera que funcione incluso con la conversión. El estándar (C17 6.3.2.3 §5 y §6 dice):

    Un entero se puede convertir a cualquier tipo de puntero. Excepto como se especificó anteriormente, el resultado está definido por la implementación, podría no estar correctamente alineado, podría no apuntar a una entidad del tipo referenciado y podría ser una representación de captura. 68)

    Cualquier tipo de puntero se puede convertir en un tipo entero. Excepto como se especificó anteriormente, el resultado está definido por la implementación. Si el resultado no se puede representar en el tipo entero, el comportamiento es indefinido. El resultado no necesita estar en el rango de valores de cualquier tipo de entero.

    Nota informativa al pie:

    68) Las funciones de mapeo para convertir un puntero a un entero o un entero a un puntero están diseñadas para ser consistentes con la estructura de direccionamiento del entorno de ejecución.

    Además, la dirección de un puntero podría ser más grande de lo que cabría dentro de un int , como es el caso de la mayoría de los sistemas de 64 bits. Por lo tanto, es mejor usar el uintptr_t de <stdint.h>

Esta pregunta pretende ser una entrada de preguntas frecuentes para toda la inicialización / asignación entre problemas de enteros y punteros.

Quiero escribir código donde el puntero se establece en una dirección de memoria específica, por ejemplo, 0x12345678 . Pero al compilar este código con el compilador gcc, obtengo "la inicialización hace que el puntero de un entero sin una conversión" advertencias / errores:

int* p = 0x12345678;

De forma similar, este código da "la inicialización hace que el entero desde el puntero sin una conversión":

int* p = ...; int i = p;

Si hago lo mismo fuera de la línea de declaración de variable, el mensaje es el mismo pero dice "asignación" en lugar de "inicialización":

p = 0x12345678; // "assignment makes pointer from integer without a cast" i = p; // "assignment makes integer from pointer without a cast"

Las pruebas con otros compiladores populares también dan mensajes de error / advertencia:

  • clang dice "conversión de entero a puntero incompatible"
  • icc dice "un valor de tipo int no se puede usar para inicializar una entidad de tipo int* "
  • MSVC (cl) dice que "inicializar int* diferencia en los niveles de direccionamiento indirecto de int ".

Pregunta: ¿Son válidos los ejemplos anteriores?

Y una pregunta de seguimiento:

Esto no da ninguna advertencia / error:

int* p = 0;

Por qué no?