Estoy leyendo este blog y en la sección puntero Nulo constantes y expresiones entre paréntesis el autor referencias § 6.3.2.3 y § 6.5.1 de la ISO estándar de C y dice:

Se no decir que un entre paréntesis puntero nulo constante es un puntero null constante.

Lo que implica que, estrictamente hablando, que (void*)0 es un puntero null
constante, pero ((void*)0) no.

A continuación:

Estoy seguro de que la mayoría de las implementaciones de hacer el tratamiento de un entre paréntesis puntero nulo constante como un puntero nulo constante, y definir NULL como 0, ((void*)0), o de alguna otra manera.

Las dos secciones que se hace referencia decir:

§ 6.3.2.3

Un entero constante de la expresión con el valor 0, o tal expresión
elenco de tipo void *, se llama a un puntero nulo constante.

§ 6.5.1

Una expresión entre paréntesis es una expresión primaria. Su tipo y valor
son idénticos a los de la unparenthesized expresión.
Es un
lvalue, una función de designación, o un vacío de expresión si el
unparenthesized expresión es, respectivamente, un lvalue, una función
designador, o un vacío de expresión.

No la negrita sentencia contradice la reclamación del autor de que ((void*)0) no es un puntero null constante?

InformationsquelleAutor user4164058 | 2014-10-21

3 Comentarios

  1. 28

    No la negrita sentencia contradice la reclamación del autor de que ((void*)0) no es un puntero null constante?

    No, no. (Confieso que es un poco sesgada, ya que el que se hace referencia blog es mío.)

    La frase en negrita dice que su tipo y valor son idénticos a los de la unparenthesized expresión. Eso no es suficiente para deducir que es un puntero null constante.

    Considerar:

    void *var = 0;

    (void*)0 es un puntero null constante. ((void*)0) tiene el mismo tipo y valor como (void*)0. var también tiene el mismo tipo y valor como (void*)0, pero var claramente no es un puntero null constante.

    Habiendo dicho eso, estoy 99+% seguro de que la intención es que ((void*)0) es un puntero null constante, y de manera más general que cualquier entre paréntesis puntero nulo constante es un puntero null constante. Los autores de la norma simplemente abandonados a decir así. Y desde la descripción de expresiones entre paréntesis en 6.5.1p5 específicamente enumera varias otras características que se heredan por expresiones entre paréntesis:

    Una expresión entre paréntesis es una expresión primaria. Su tipo y valor
    son idénticos a los de la unparenthesized expresión. Es un
    lvalue, una función de designación, o un vacío de expresión si el
    unparenthesized expresión es, respectivamente, un lvalue, una función
    designador, o un vacío de expresión.

    la omisión es preocupante (pero sólo ligeramente de modo).

    Pero supongamos que, por el bien del argumento, que ((void*)0) no es un puntero null constante. ¿Qué diferencia hace?

    (void*)0 es un puntero null constante, cuyo valor es un puntero nulo de tipo void*, así que por la semántica de expresiones entre paréntesis ((void*)0) también tiene un valor que es un puntero nulo de tipo void*. Ambos (void*)0 y ((void*)0) son dirección constantes. (Bueno, yo pensar lo están). Entonces, ¿qué contextos requieren un puntero nulo constante y no aceptan un dirección constante? Hay sólo unos pocos.

    6.5.9 operadores de Igualdad

    Una expresión de la función de puntero de tipo se puede comparar la igualdad a un puntero nulo constante. (Un puntero a un objeto puede ser comparado con una expresión de tipo void*, sino un puntero a función no puede, a menos que sea un puntero nulo constante.) Así que este:

    void func(void);
    if (func == ((void*)0)) { /* ... */ }

    sería una violación de la restricción.

    6.5.16.1 asignación Simple

    De una asignación, un puntero nulo constante puede ser asignado a un objeto de puntero-a-función de tipo, y se convierte de forma implícita. Una expresión de tipo void* que no es un puntero null constante no puede ser asignado a un puntero a función. Las mismas restricciones se aplican a argumento pasando y la inicialización. Así que este:

    void (*fp)(void) = ((void*)0);

    sería una violación de la restricción de si ((void*)0) no eran un puntero nulo constante. Gracias a comentarista hvd para encontrar esto.

    7.19 definiciones Comunes <stddef.h>

    La macro NULL se expande a «una aplicación definida por el puntero nulo constante». Si ((void*)0) no es un puntero null constante, entonces:

    #define NULL ((void*)0)

    no sería válida. Esta sería una restricción impuesta sobre la aplicación, no en los programadores. Tenga en cuenta que este:

    #define NULL (void*)0

    es definitivamente no válido, ya que las definiciones de macro en las cabeceras estándar debe ser plenamente protegido por los paréntesis donde sea necesario (7.1.2p5). Sin los paréntesis, la expresión válida sizeof NULL sería un error de sintaxis, expandiéndose a sizeof (void*) seguido por una extraña constante 0.

    • Una detracción: hacer de su argumento ejecutar a través de void* var tiene la debilidad de que var no es un puntero null constante porque también pasa por no ser una de HIELO.
    • Usted puede elaborar un poco sobre lo que «no es un puntero nulo constante» significa? Quiero decir, var no lo es porque no es una constante, pero, ¿qué significa para ((void*)0) no ser uno? ¿Hay algún tipo de perverso compilador de comportamiento que es técnicamente permitido por la especificación debido a este descuido?
    • 6.3.2.3 Cláusula 4: la Conversión de un puntero nulo a otro tipo de indicador de los rendimientos de un puntero nulo de ese tipo. Cualquiera de los dos punteros null deberá comparar la igualdad.
    • Sólo la meditación, la oración anterior dice que «si un puntero nulo constante se convierte en un tipo de puntero, el puntero resultante [es] llamado a un puntero nulo». Una interpretación estricta podría sugerir que weird no se necesita ser un puntero nulo en caso de que la conversión no se produce porque ((void*)0) no es un puntero null constante en el primer lugar. Y si weird no es un puntero nulo, entonces no es necesario que comparar igual a uno. Naturalmente, todo esto es una tontería si el acto de añadir paréntesis para (void*)0 constituye por sí misma una conversión a un tipo de puntero, que es probable que si ((void*)0) es de tipo puntero.
    • En otras palabras, si ((void*)0) es no un puntero nulo constante, pero es un puntero nulo, entonces 6.3.2.3.4 parecería sugerir que todo está bien, ya que siempre se puede convertir a otro tipo de puntero.
    • Si no es un puntero null constante, sin duda, es una dirección constante con valor de puntero nulo, que es utilizable todos los mismos lugares.
    • La adscripción de Ben, que es indignante; todos Estamos de acuerdo en que void *weird = ((void*)0); hace wierd un puntero nulo, porque incluso si ((void*)0) no eran un puntero nulo constante (que creo que es), entonces debe ser un válido de puntero nulo en el inicializador, porque «Su tipo y valor son idénticos a los de la unparenthesized expresión». Y porque el unparenthesized expresión de la voluntad de tener éxito en la fabricación wierd un NULL puntero, por lo que se la admite paréntesis uno.
    • Seguro, pero la cuestión parece ser, ¿cómo llegar a esa conclusión a partir de la redacción de la norma? No creo que nadie está sugiriendo que C está diseñado para funcionar en algunos completamente extraña manera en la que la presencia o ausencia de paréntesis que transforma por completo el comportamiento de la asignación, sólo si hay una cierta técnica de omisión en las palabras.
    • Gracias! +1
    • Simplemente la conversión de ((void*)0) a un puntero-a-función tipo es suficiente para demostrar el problema, incluso sin ningún tipo de comparaciones: void (*fp)(void) = ((void*)0); es válido si y sólo si ((void*)0) es un NPC. Quizás también es interesante que C++ ha sustituido a la semántica de los paréntesis con una mucho más simple: «La expresión entre paréntesis se pueden utilizar exactamente de la misma en contextos como aquellos donde la expresión entre comillas puede ser utilizado, y con el mismo significado, salvo indicación en contrario.» Esto también afecta, por ejemplo, char str[] = ("abc");, que es válido en C++, pero no en C.
    • Buena captura; he añadido que a mi respuesta. (Yo la culpa de los torpes en la funcionalidad de búsqueda de mi visor de PDF.)
    • Hay otros casos que sizeof NULL donde la falta de paréntesis en (void*)0 sería un problema? ¿Hay alguna razón sizeof NULL se debe esperar a que tienen un significado especial, ya que los diferentes tipos de punteros pueden tener tamaños diferentes de representaciones?
    • En la práctica, no existen casos donde la falta de paréntesis es un problema, porque no conformes aplicación utiliza #define NULL (void*)0. Considero que es una suerte que los autores de la norma no arbitrariamente afloje los requisitos, porque se presume que algunos particulares de construcción no sería útil o significativo, especialmente cuando los requisitos de imponer esencialmente cero costo. Puede usted pensar en alguna razón, incluso si estuviera permitido, tener #define NULL (void*)0 en lugar de #define NULL ((void*)0)?
    • Tener NULL ser un puntero nulo constante sería útil, ¿no?
    • Qué? NULL es un puntero nulo constante, por definición. Me gustaría defensor de la fijación de la descripción de expresiones entre paréntesis para aclarar que ((void*)0) es una definición válida para NULL. El cambio de la norma para permitir (void*)0 como válida la definición de NULL sería absurdo.
    • ¿En qué casos sería (void*)0 ser evidentemente diferente de ((void*)0)? En los sistemas en los diferentes tipos de punteros tienen diferentes tamaños, tener un compilador de graznar en sizeof NULL parece mejor que la de tener que informar de algo que no puede ser el tamaño de uno está interesado en. ¿En qué otro contexto sería (void*)0 comportarse evidentemente diferente de ((void*)0)?
    • No me importa. Un conformes compilador debe manejar sizeof NULL — y hasta donde yo sé, los compiladores existentes no tienen un problema con él. Eso no significa que usted tiene que utilizar en el código. Los compiladores pueden advertir sobre algo que les gusta.
    • Para qué propósitos no se las ingenió programa desea utilizar una expresión que podría producir el tamaño de un «int» o el tamaño de un «void*»?
    • Estoy hecho aquí.

  2. 7

    Es una expresión entre paréntesis que contiene un puntero nulo constante, por lo que indiscutiblemente es un valor de puntero nulo. Usando como un r-value tiene exactamente el mismo efecto que el uso de la «conforme» de la versión como un r-valor.

    Si hay algunas reglas sintácticas que podría sólo aceptar un puntero nulo constante, no califican. Pero yo no soy consciente de ninguna (aunque no soy tan experto en C).

    Y aunque ninguno de los dos es un constante (refiriéndose a la gramática formal de la producción), ambos pueden aparecer en una expresión constante en un inicializador, porque ambos puntero nulo constantes y dirección constantes son permitidos, y una constante de puntero nulo valor está explícitamente incluido en la categoría de dirección constante.

    Puntero comparaciones también mencionar específicamente puntero nulo constantes… pero aquí puntero de valores también son aceptados, y todos los valores de puntero nulo son tratados por igual. Mismo para el ternario y operadores de asignación.

    Por favor, sea consciente de que estas reglas son muy diferentes en C++, donde tanto las expresiones anteriores son constantes a valores de puntero nulo de tipo void*, pero no universal puntero nulo constantes. Puntero nulo constantes en C++ son integral expresiones constantes que evaluar a cero. Y void* no convertir implícitamente a otros tipos de puntero.

    • Cómo es «ni [(void*)0 o ((void*)0)] una constante»? El estándar de reclamaciones explícitamente que (void*)0 es un puntero null constante.
    • Hay una gramática de producción para constante, que incluye sólo a los integer-constante, flotante constante, enumeración constante, y personaje-constante. Estos valores de puntero son expresiones constantes, pero no constantes. Su concepto de que la palabra «constante» abarca todo tipo de constante entera, dirección constante, puntero nulo constante, y así sucesivamente simplemente no tienen aquí; las reglas habituales de la lengua inglesa no se aplican, la gramática formal hace.
    • Tal vez usted podría entonces explicar que el uso de constante como «Y aunque ninguno de los dos es un sintáctica constante, tanto de…»?
    • Resulta que hay al menos un contexto donde un puntero nulo constante es permitida, pero ((void*)0), si no fuera un NPC no sería. Una expresión de puntero-a-función de tipo se puede comparar la igualdad o la desigualdad a un puntero nulo constante, pero no a cualquier otra expresión de la constante de tipo void*. Ver mi respuesta actualizada para más detalles.
  3. -3

    Intente imprimir por debajo de la línea de tu código C:

    printf(«%p»,(void*)0);

    Obtendrá la salida como:

    (nil)

    • Que usted también conseguirá para (char*)0, o (void*){0} pero (char*)0 y (void*){0} no son puntero nulo constantes mientras (void*)0 es.

Dejar respuesta

Please enter your comment!
Please enter your name here