que - punteros como parametros de funciones en c
Desreferenciando un puntero a 0 en C (5)
¿Cómo las personas realmente usan 0x0 cuando es necesario?
Por ambos:
- escribir el código requerido en lenguaje ensamblador, o
- escribir el código en C y verificar que su compilador genera el lenguaje ensamblador correcto para la operación deseada
A veces los datos en la dirección de memoria 0x0 son bastante valiosos: tome el IVT en modo real x86 como un ejemplo más conocido: comienza en 0x0 y contiene punteros para interrumpir manejadores: un dword en 0x00 es un puntero al controlador de error de división por cero.
Sin embargo, el estándar de lenguaje C11 prohíbe la eliminación de referencia de punteros nulos [WG14 N1570 6.5.3.2], que se definen como punteros inicializados con 0 o punteros inicializados con un puntero nulo [WG14 N1570 6.3.2.3], que prohíben efectivamente el primer byte.
¿Cómo las personas realmente usan 0x0 cuando es necesario?
Anexo J Es un comportamiento indefinido cuando ...
El operando del operador unario * tiene un valor no válido (6.5.3.2).
En esa misma nota que mencionaste, dice que un puntero nulo es un valor inválido. Por lo tanto, no está prohibido, sino un comportamiento indefinido. En cuanto a la distinción entre la dirección 0x0
y un puntero nulo, consulte ¿Se puede utilizar la dirección de memoria 0x0? .
El puntero nulo no es necesariamente la dirección 0x0, por lo que potencialmente una arquitectura podría elegir otra dirección para representar el puntero nulo y podría obtener 0x0 de nuevo como una dirección válida.
Si el puntero nulo está reservado por el sistema operativo o la implementación de C ++ no está especificado, pero el nuevo no devolverá un puntero nulo, cualquiera que sea su dirección (nothrow new es una bestia diferente). Por lo tanto, para responder a su pregunta:
¿Es útil la dirección de memoria 0x0?
Tal vez, depende de la implementación / arquitectura particular.
En otras palabras, puede usar 0x0
si está seguro de que no provocará un bloqueo.
C no prohíbe la desreferenciación del puntero nulo, simplemente lo convierte en un comportamiento indefinido.
Si su entorno es tal que puede desreferenciar un puntero que contiene la dirección 0x0
, entonces debería poder hacerlo. El estándar de lenguaje C no dice nada sobre lo que sucederá cuando lo haga. (En la mayoría de los entornos, el resultado será un bloqueo del programa).
Un ejemplo concreto (si recuerdo esto correctamente): en las computadoras Sun 3 basadas en 68k, eliminar la referencia de un puntero nulo no causaba una trampa; en su lugar, el SO almacenaba un valor cero en la dirección cero de la memoria, y la desreferenciación de un puntero nulo (que apuntaba a la dirección cero) produciría ese valor cero. Eso significaba, por ejemplo, que un programa C podría tratar un puntero nulo como si fuera un puntero válido a una cadena vacía. Algún software, intencionalmente o no, dependía de este comportamiento. Esto requirió una gran cantidad de limpieza al portar el software al Sun 4 basado en SPARC, que atrapó las desreferencias del puntero nulo. (Recuerdo claramente haber leído sobre esto, pero no pude encontrar una referencia; lo actualizaré si puedo encontrarlo).
Tenga en cuenta que el puntero nulo no es necesariamente la dirección cero. Más precisamente, la representación de un nulo puede o no ser todo-bits-cero. Es muy común, pero no está garantizado. (Si no es así, entonces la conversión de entero-a-puntero de (void*)0
no es trivial.)
La sección 5 de las preguntas más frecuentes sobre comp.lang.c analiza los punteros nulos.
El sistema operativo usa una tabla de punteros para interrumpir las rutinas y llamar a la (s) interrupción (es) apropiada (s). Generalmente (en la mayoría de los sistemas operativos) la tabla de punteros se almacena en poca memoria (los primeros cientos o más lugares). Estas ubicaciones contienen las direcciones de las rutinas del servicio de interrupción para los distintos dispositivos.
Entonces cuando lo haces
char *ptr = 0x0;
entonces lo más probable es que esté inicializando su puntero con la dirección de una rutina de servicio de interrupción. La desreferenciación (o modificación) de una ubicación de memoria que pertenece al sistema operativo probablemente causa la falla del programa.
Por lo tanto, mejor no inicializar un puntero a 0x0
y desreferenciarlo hasta que tenga la confirmación de que no pertenece al sistema operativo.
La declaración:
char * x = 0;
no necesariamente pone 0x0 en x. Pone el valor del puntero nulo definido para la arquitectura actual y el compilador en x.
Ahora, en términos prácticos, todos los compiladores / procesadores observados de uso común terminan poniendo 32 (o 64) 0 bits en una fila en un registro o ubicación de almacenamiento en respuesta a esa declaración, entonces, si la dirección de memoria 0 es útil, luego, como otros han indicado, estás estancado usando un comportamiento formalmente indefinido. Sin embargo, en el pasado existía hardware para el cual un ''puntero nulo'' era un patrón de bit que no era todo ceros, y quién sabe, puede haberlo otra vez.