2010-01-03 30 views
7
#include<iostream> 
using namespace std; 

int main() 
{ 
    int *p,*c; 
    p=(int*)10; 
    c=(int*)20; 
    cout<<(int)p<<(int)c; 
} 

Alguien me preguntó "¿Qué pasa con el código anterior?" y no pude resolverlo Que alguien me ayude por favor.Casting entre enteros y punteros en C++

+0

+1, buena pregunta: -) ..... –

+1

¿Ha considerado esto como la respuesta válida: "nada". Un entrevistador generalmente está interesado en * cómo * se llega a una respuesta, no a la respuesta. –

+1

un nombre más descriptivo no dolería. – jalf

Respuesta

8

Algunos querían una cita de la norma C++ (que tendría que poner esto en los comentarios de esa respuesta si el formato de comentarios no fue tan restringido), aquí están dos del 1999 uno:

5.2 .10/3

La asignación realizada por reinterpret_cast está definida por la implementación.

5.2.10/5

Valor de tipo integral o tipo de enumeración se puede convertir explícitamente a un puntero. Un puntero convertido a un número entero de tamaño suficiente (si existe tal en la implementación) y de vuelta al mismo tipo de puntero tendrá su valor original; las asignaciones entre los punteros y los enteros están definidos por la implementación.

Y no veo nada obligatorio que tal mapeo definido por implementación debe dar una representación válida para todas las entradas. De lo contrario, dijo, una implementación de una arquitectura con registros de direcciones puede atrapar muy bien al ejecutar

p = (int*)10; 

si el mapeo no da una representación válida en ese momento (sí, lo que es una representación válida para un puntero puede depender de Por ejemplo, delete puede invalidar la representación del puntero eliminado).

+0

Upvoted para la segunda cita. C-style cast y reinterpret_cast tienen un comportamiento diferente, por lo que no estoy seguro de que se aplique la primera cita. –

+3

Dan, toda la sección 5.2.10 se trata de reinterpret_cast, por lo tanto, ambas citas se refieren a reinterpret_cast. Pero en C++, la sintaxis de Ccast se define en términos de los otros moldes, y en este caso, es la definición de reinterpret_cast la que se aplica. – AProgrammer

+0

@AProgrammer: Gracias, no pude encontrarlo en el Estándar C++ :) –

9

El hecho de que int y los tipos de datos de puntero no tengan la misma cantidad de bits, de acuerdo con el estándar C++, es una cosa: eso significa que puede perder precisión.

Además, emitir un int a un int puntero y luego otra vez es tonto. ¿Por qué no simplemente dejarlo como int?

De hecho, hice intenté compilar esto en gcc y funcionó bien, pero eso es probablemente más accidental que un buen diseño.

+1

Creo que captó el propósito de la pregunta (que es claramente una pregunta engañosa para una entrevista o algo así), pero supongo que el código mostrará el comportamiento previsto en cualquier plataforma donde tanto int como int * puedan representar los valores 10 y 20 –

+1

Dan es correcto: el código, tal como está escrito, funcionará en la mayoría de las plataformas modernas. Pero el uso de punteros para almacenar enteros generalmente causará bloqueos u otros errores si desreferencia esos punteros. Ocasionalmente ves personas que realmente saben lo que hacen escribir código como este, pero considero que es una práctica dudosa que generalmente se debe evitar. Como dicen en Mythbusters, "¡Por favor, no intentes esto en casa!" –

+1

@Bob Con más frecuencia, ves personas que realmente NO saben lo que están haciendo escribiendo código como este. –

0

Está asignando valores (10 y 20) a los punteros, lo que obviamente es un problema potencial si intenta leer los datos en esas direcciones. Lanzar el puntero a un número entero también es realmente feo. Y su función principal no tiene una declaración de devolución. Eso es solo algunas cosas.

+1

main() no necesita una declaración de devolución. El compilador que cumple con los estándares lo inserta. http://www2.research.att.com/~bs/bs_faq2.html, refiérase a la pregunta "¿Puedo escribir" void main() "?. – Jagannath

+0

Puede escribir" void main() "que sería mejor en mi humilde opinión Sé que el compilador agrega la declaración de retorno, pero no es una buena práctica escribir código con un montón de advertencias al compilar y, básicamente, todo lo que está mal con el código generaría advertencias de compilación, así que mi punto es: active todas las advertencias y usted ' Veremos cómo obtener ayuda del compilador para saber "qué está mal con el código". – Cellfish

1

Suponiendo que tengo razón en lo que esto se supone que es, debería tener este aspecto:

int main() 
{ 
    int *p, *c; 
    // Something that creates whatever p and c point to goes here, a trivial example would be. 
    int pValue, cValue; 
    p = &pValue; 
    c = &cValue; 
    // The & operator retrieves the memory address of pValue and cValue. 

    *p = 10; 
    *c = 20; 
    cout << *p << *c; 
} 

Con el fin de asignar o recuperar un valor a una variable referenciado por un puntero, es necesario dereference eso.

Lo que está haciendo su código es convertir 10 en puntero a int (que es la dirección de memoria donde reside el int real).

+2

Esto segmentará la falla en la mayoría de las implementaciones. –

+0

Desreferenciar un "puntero salvaje" es Comportamiento indefinido. –

+1

@Adam, le daré el beneficio de la duda y supongo que usted quiso decir "así debería ser el código * de su problema" en lugar de "este código es la solución a su problema". Como p y c no están inicializados, se pueden establecer en * cualquier cosa *, que es un comportamiento indefinido. – paxdiablo

0

las direcciones p y c pueden ser mayores que int.

+0

o menor que int – swegi

+0

@fupsduck: Las direcciones p y c serán del mismo tamaño que las de un int. Todos los punteros son de 32 bits, lo mismo que el tamaño int. – goldenmean

+1

@goldenmean, punteros de 64 bits y 32 bits de entrada no son una rareza en estos días. – AProgrammer

-1

hay más o menos todo lo malo en ello:

int *p,*c; 
p=(int*)10; 
c=(int*)20; 
  • después p está apuntando a la dirección de memoria 10
  • después c está apuntando a la dirección de memoria 20

Esto no tiene No se ve muy intencional.

Y supongo que todo el programa simplemente se bloqueará.

+3

No, no se bloqueará, siempre que no intente utilizar esos punteros para * referencia * direcciones de memoria 10 y 20. –

+0

Todo dependiendo del nivel de protección de la memoria aplicada, aunque ... – e8johan

+0

@Bob: Podría colapsar. Está definido por la implementación. La CPU podría detectar que estos son punteros no válidos y atrapar tan pronto como se creen los punteros. – jalf

0

El problema en algunas plataformas que necesita

p = (int*) (long) 10; 

documentación Ver GLIB en type conversion macros.

Y para las personas que quizás no encuentren un uso para este tipo de expresiones, es posible devolver datos dentro de las funciones de devolución del valor del puntero. Puede encontrar ejemplos del mundo real, donde en este caso es mejor usar este modismo, en lugar de asignar un nuevo entero en el montón, y devolverlo: bajo rendimiento, fragmentación de la memoria, simplemente feo.