2011-08-20 6 views
14

Como saben, en lenguaje C estándar moderno del 0 Valor constante de contexto puntero actúa como un nulo puntero constante, que se convierte en una plataforma específica (y posiblemente incluso el tipo específico) valor nulo triple .¿Cuándo la constante 0 en el contexto del puntero adquiere su estado especial?

Mientras tanto, las primeras versiones del lenguaje C, como la descrita en C Reference Manual, no distinguían mucho entre contextos de punteros y enteros, lo que permite comparar y asignar enteros libremente a los punteros. Si no estoy equivocado, en esa versión de C la constante 0 no tenía un estado especial, lo que significa que asignar el valor de la constante 0 a un puntero simplemente lo haría apuntar a la dirección física 0 (igual que asignar el valor de 42 a un puntero hacer que apunte a la dirección física 42).

En ANSI C las cosas han cambiado significativamente. Ahora la asignación de la constante 0 a un puntero colocará un valor de puntero nulo específico de la plataforma en ese puntero. El valor del puntero nulo no se requiere para ser representado por el valor 0 físico.

Entonces, ¿en qué punto de la historia del lenguaje C cambió de uno a otro? ¿K & R C ya incorpora el concepto de alto nivel de null-pointer con constante 0 dado su estado especial? ¿O la K & R C todavía garantiza la asignación física de enteros a punteros incluso para la constante 0?

+1

"Ahora asignar la constante 0 a un puntero colocará algún valor de puntero nulo específico de la plataforma en ese puntero." Esto es nuevo para mi; es realmente cierto? ¿Cuál es la plataforma/compilador más comúnmente utilizado donde esto es cierto, es decir, donde 'void * x = 0;' escribe un valor físico distinto de 0 en 'x'. –

+1

@David Grayson: Bueno, primero, esto es realmente cierto, sí. En el nivel de lenguaje abstracto, por supuesto. En segundo lugar, la mayoría (todas) de las plataformas populares de hoy usan la dirección 0x0 como valor de puntero nulo, por lo que de hecho verá 0 en su puntero.Conceptualmente, sin embargo, no es la misma integral 0 que le asignó :) En tercer lugar, C FAQ (http://c-faq.com/null/machexamp.html) tiene algunos ejemplos de plataformas [exóticas] con un valor no nulo punteros nulos. En cuarto lugar, no hay nada que evite que uno tome las fuentes de GCC y las modifique para usar un valor físico distinto de cero para los null-punteros (si uno no tiene nada mejor que hacer). – AnT

+0

¡Gracias por el enlace a las preguntas frecuentes de mi pregunta! Parece que todas las máquinas mencionadas son realmente viejas. No voy a perder el sueño por usar un 0 en un lugar donde NULL sería suficiente, pero puedo entender por qué los puristas se estremecerían. –

Respuesta

8

Vuelve a casi al principio de C (si no es el principio). Si nos fijamos en la página 21 de la January 1974 C reference manual, es más o menos declarado directamente en un código de ejemplo:

/* is pointer null? */ 
if (p == 0) { 

Volviendo todavía un poco más lejos, a ca. 1972-73 PDP-11/20 compiler, encontramos:

match(tree, table, nreg) 
int tree[], table[]; { 
    extern opdope[], dcalc, notcompat; 
    int op, d1, d2, t1, t2, p1[], p2[]; 
    char mp[]; 

    if (tree==0) 
     return(0); 
    op = *tree; 

Al menos si estoy leyendo esto correctamente, la línea if (tree==0) está comprobando que tree es un puntero no nulo antes de intentar desreferenciarlo.

Desafortunadamente, Dennis says no puede estar mucho más seguro acerca de la fecha que "1972-73".

No hay mucha historia de C antes de eso. Sin embargo, parece que hay un poco de historia de 0 siendo tratado como un puntero nulo. Me parece que el uso de 0 como puntero nulo es algo que C "heredó" de Unix. La entrada para exec en el November 1971 1st Edition Unix programmer's manual muestra un puntero con el valor 0 para indicar el final de la lista de argumentos. De acuerdo con Dennis' description, en este punto "C estaba por venir".

En base a todo esto, concluiría tentativamente que C trató 0 como un puntero nulo desde el principio, o al menos tan pronto probablemente ya no haya ningún registro de una versión del lenguaje que fuera diferente.

No he tenido tanto éxito en rastrear la documentación sobre el primer punto en el que un puntero nulo podría haber tenido bits distintos de cero. Desde el punto de vista del idioma, esto tiene nunca sido relevante. Sospecho que sucedió bastante temprano, pero encontrar documentación para apoyar eso sería difícil. Uno de los primeros puertos de C era IBM System/360 mainframes, y aunque no puedo encontrar documentación directa de él, mi conjetura sería que internamente el valor nulo del puntero utilizado en estas máquinas probablemente no era cero. No tengo el número exacto a mano, pero sé que PL/I en estas máquinas usó un valor distinto de cero para su equivalente de un puntero nulo; Me gustaría suponer que cuando portaron C a estas máquinas, probablemente usaron el mismo valor.

+0

Vi los comentarios en CRM, pero es bastante obvio para mí que el puntero nulo en ese caso representa el puntero de cero dirección física. La parte "normativa" del documento en sí (si se puede llamar así) no menciona ningún apuntador nulo. Básicamente, en CRM el "puntero nulo" era solo un acuerdo de caballeros sin el apoyo del idioma. Con el mismo grado de éxito, podrían haber decidido usar un puntero (dirección 0x1) como valor "especial" para los punteros. – AnT

+0

Mi pregunta es sobre una cosa totalmente diferente. Mi pregunta es sobre el momento en el que C comenzó a permitir representaciones distintas de cero para los punteros nulos. Es decir. uno hace 'p = 0', pero uno obtiene' p' que apunta a una dirección física distinta de cero. ANSI C permite que este sea el caso. ¿Cuándo se permitió esto? – AnT

+0

@AndreyT: Eso es lo que trato en mi último párrafo. Supongo que nunca fue rechazado, pero * probablemente * se usó por primera vez cuando C se transfirió a mainframes System/360 (aunque no he encontrado ninguna documentación directa de eso). –

3

See the C-faq question 5.4

Como una cuestión de estilo, muchos programadores prefieren no tener sin adornos dispersos a través de sus programas, algunos números que representan de 0 y algunos indicadores que representan. Por lo tanto, el preprocesador macro NULL está definido (por varios encabezados, incluyendo y) como una constante de puntero nulo, generalmente 0 o ((void *) 0) (ver también la pregunta 5.6). Un programador que desee hacer explícita la distinción entre 0 el entero y 0 la constante del puntero nulo puede usar NULL siempre que se requiera un puntero nulo.

Usar NULL es solo una convención estilística; el preprocesador vuelve NULL a 0, que el compilador reconoce en contextos de puntero, como antes. En particular, aún se puede necesitar un lanzamiento antes de NULL (como antes de 0) en un argumento de llamada de función. La tabla de la pregunta 5.2 anterior se aplica para NULL así como para 0 (un NULL sin adornos es equivalente a 0 sin adornos).

NULL debe usarse solo como una constante de puntero; ver la pregunta 5.9.

References: K&R1 Sec. 5.4 pp. 97-8 
K&R2 Sec. 5.4 p. 102 
ISO Sec. 7.1.6, Sec. 6.2.2.3 
Rationale Sec. 4.1.5 
H&S Sec. 5.3.2 p. 122, Sec. 11.1 p. 292 

What is this infamous null pointer anyways?

La definición del lenguaje establece que para cada tipo de puntero, hay un valor especial - el "puntero nulo" - que se distingue de todos los demás valores de puntero y que está "garantizado para compare desigual a un puntero a cualquier objeto o función ". Es decir, un puntero nulo apunta definitivamente a ninguna parte; no es la dirección de ningún objeto o función. El operador de dirección & nunca arrojará un puntero nulo, ni una llamada exitosa a malloc. [Nota al pie] (malloc devuelve un puntero nulo cuando falla, y este es un uso típico de punteros nulos: como un "especial" valor del puntero con algún otro significado, generalmente "no asignado" o "sin apuntar a ningún lado todavía")

Un puntero nulo es conceptualmente diferente de un puntero no inicializado. Se sabe que un puntero nulo no apunta a ningún objeto o función; un puntero no inicializado podría apuntar a cualquier parte. Ver también las preguntas 1.30, 7.1 y 7.31.

Como se mencionó anteriormente, hay un puntero nulo para cada tipo de puntero, y los valores internos de punteros nulos para diferentes tipos pueden ser diferentes. Aunque los programadores no necesitan conocer los valores internos, siempre se debe informar al compilador qué tipo de puntero nulo se requiere, de modo que pueda hacer la distinción si es necesario (ver preguntas 5.2, 5.5 y 5.6).

References: K&R1 Sec. 5.4 pp. 97-8 
K&R2 Sec. 5.4 p. 102 
ISO Sec. 6.2.2.3 
Rationale Sec. 3.2.2.3 
H&S Sec. 5.3.2 pp. 121-3 

Por último, sólo constantes expresiones integrales con valor 0 están garantizados para indicar punteros nulos.

+0

Estoy bastante seguro de que AndreyT sabe _what_ 'NULL' es. –

+0

@James: No sé lo que él sabe ... ¡Esto no es solo para él, sino también para los futuros transeúntes! –

+2

@ Código Mono: Bueno, de eso no se trata mi pregunta. Realmente no se trata de lo que es el puntero nulo. Como señaló James, sé perfectamente qué es. La pregunta es: ¿en qué momento de la historia del lenguaje C apareció el concepto * moderno * de "puntero nulo"? También se pueden encontrar menciones de "puntero nulo" en CRM, pero allí solo representa un puntero a la dirección 0. El concepto moderno de * valor de puntero nulo * aún no existía en CRM. ¿Cuándo apareció primero? ANSI C? ¿K & R C se quedó con CRM o ya era como ANSI C en ese sentido? – AnT

Cuestiones relacionadas