2010-02-15 13 views
6

El título casi lo dice todo, pero voy a replantear la pregunta ...¿El siguiente programa es un programa C99 estrictamente conforme?

¿El siguiente programa es un "programa estrictamente conforme" bajo el estándar C99?

#include <stdlib.h> 
/* Removing any pre-existing macro definition, in case one should exist in the implementation. 
* Seems to be allowed under 7.1.3 para 3, as malloc does not begin with _X where X is any capital letter. 
* And 7.1.4 para 1 explicitly permits #undef of such macros. 
*/ 
#ifdef malloc  
#undef malloc  
#endif    

/* Macro substitution has no impact on the external name malloc 
* which remains accessible, e.g., via "(malloc)(s)". Such use of 
* macro substitution seems enabled by 7.1.4 para 1, but not specifically 
* mentioned otherwise. 
*/ 
void * journalling_malloc(size_t size); 
#define malloc(s)  ((journalling_malloc)(s))  

int main(void) 
{ 
    return malloc(10) == NULL ? 1 : 0;  
    /* Just for the sake of expanding the 
    * macro one time, return as exit code 
    * whether the allocation was performed. 
    */ 
} 
+0

BTW, soy consciente de que uno también querría 'envolver' gratis(), realloc(), strdup(), calloc() y quién sabe qué otra cosa. Esa no es la pregunta. En una nota al margen: ¿quién sabe qué más? Esas son todas las API malloc() que puedo conjurar desde lo más alto de mi cabeza. –

+2

Solo quiero mencionar que este método no ayudará con el uso de malloc en ninguna biblioteca externa. Varias personas ofrecen implementaciones de malloc alternativas que se pueden agregar en el tiempo de enlace, por ejemplo, google en http://code.google.com/p/google-perftools/wiki/GooglePerformanceTools – gnud

Respuesta

11

Veamos cuál es el estándar C99 tiene que decir al respecto:

véase 7.1.3, § 1, cláusula 5:

Cada identificador con el ámbito de archivo que aparece en cualquiera de las las siguientes subcláusulas [...] están reservadas para su uso como macro nombre y como un identificador con alcance de archivo en el mismo espacio de nombre si se incluye cualquiera de sus encabezados asociados.

y cuando incluya stdlib.h, el nombre malloc está reservado para su uso como un nombre de macro.

Pero 7.1.4, § 1 permite el uso de nombres reservados #undef:

El uso de #undef para eliminar cualquier definición de la macro también se asegurará de que una función real se conoce.

Esto hace que sea posible para volver a #definemalloc, que se traduce en un comportamiento no definido de acuerdo con 7.1.3, § 2:

Si el programa [...] define un identificador reservado como una nombre de macro, el comportamiento no está definido.

¿Por qué el estándar establece esta restricción? Porque otras funciones de la biblioteca estándar pueden implementarse como macros funcionales en términos de la función original, por lo que ocultar la declaración podría romper estas otras funciones.

En la práctica, que debe estar bien, siempre y cuando su definición de malloc satisface todas las disposiciones de la norma prevé la función de la biblioteca, lo cual puede lograrse envolviendo una llamada real a malloc().

+0

¡Buenas habilidades de lectura! Si no le molesta, ¿puedo preguntar si puede encontrar la misma respuesta para C89 y aumentar su respuesta aquí? Si lo hiciera, cambiaré el título de esta pregunta. Tal sería un mejor recurso. Depende de usted. –

+0

@Heath: la sección 4.1.2 del borrador de ANSI no es muy detallada, pero dice que "Todos los identificadores externos declarados en cualquiera de los encabezados están reservados, se haya incluido o no el encabezado asociado"; la nota al pie 87 básicamente implica la misma semántica que C99 para este caso de uso – Christoph

+2

por cierto: puede hacer que el programa se conforme al no incluir 'stdlib.h' y declarar' malloc() 'usted mismo, lo cual está explícitamente permitido por 7.1.4 §2 – Christoph

3

Usted tendrá que cambiar journalling_malloc(...)void-void *, cambiar los comentarios a // (porque están comentando su UNDEF) y añadir un #endif cerca de la parte superior, pero por lo demás se ve bien.

+0

Buena captura, gracias. Quise decir que era algo que compilaría, e hice el cambio que sugeriste. ;) –

+3

Debo agregar que no es necesario ajustar #undef en un condicional. Está bien #undef algo que no está definido. – DigitalRoss

+0

oh hombre gracias por ser mi compilador humano. :) –

1

Funcionará: Sí.

¿Es conformes: Nº

De acuerdo con la Norma C:

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf

Todos los nombres de la biblioteca estándar están reservados (incluyendo malloc).

7.1.3 Reserved identifiers 
Specifically: 
    <quote>Each macro name in any of the following subclauses</quote> 
    <quote>All identifiers with external linkage in any of the 
    following subclauses</quote> 

también un programa estrictamente conformación voluntad no puede definir los nombres que están reservados para la ejecución (es decir Esto incluye nombres y idnetifiers reservadas, los de las bibliotecas actuales y los reservados para uso futuro).

7.1.3 (note 2) 
Specifically: 
    <quote>If the program declares or defines an identifier in a context in which 
    it is reserved or defines a reserved identifier as a macro name, 
    the behavior is undefined.</quote> 

Por definición: defining malloc() es no conforme porque es un comportamiento indefinido (Ilegal).

+0

¿Eso significa que diría que según C99, los nombres de macro son parte del espacio de nombre "identificador ordinario" definido en la sección 6.2.3, para 1, 4º elemento de viñeta? Lo pregunto porque pareces estar diciendo que los nombres de las macros entran en conflicto con los identificadores ordinarios. –

0

identificadores de macro son nombres propios, y todos los identificadores de la biblioteca de cualquier tipo están prohibidos de aliasing a una macro independientemente de la situación lingüística de las macros.

§6.10.3/7

El identificador inmediatamente después la definen se llama el nombre de macro. Hay un espacio de nombre para la macro nombres.

§7.1.3/1

Cada identificador con alcance de archivo enumerados en cualquiera de las siguientes subcláusulas (incluyendo la futura biblioteca direcciones) está reservado para uso como un nombre de macro y como un identificador con ámbito de archivo en el mismo espacio de nombres si cualquiera de sus cabeceras asociada es incluido.

§7.1.3/2

Si el programa declara o define un identificador en un contexto en el que es reservados (que no sea permitida por 7.1.4), o define un identificador reservado como nombre de macro, el comportamiento no está definido.

+0

¿Está de acuerdo 7.1.3/3 especifica que se le permitiría a #undef malloc? Si es así, ¿está diciendo que el lenguaje de 7.1.3/1 sin embargo haría que no se conformes #define malloc independientemente de #undef? Además, sí vio que los nombres de macro no pueden ser "identificador con alcance de archivo" porque 6.2.1/1 hace una declaración específica sobre el estado lingüístico de las macros. (6.2.1 es la sección "ámbito de identificador", donde "ámbito de archivo" se define para identificadores que no sean nombres de macros.) –

+0

@Heath: 7.1.3/3 solo prohíbe cosas ("el comportamiento no está definido") y solo se refiere a todos los identificadores que comienzan con guión bajo, que 'malloc' (al menos) no lo es. Es irrelevante que las macros no sean identificadores con alcance de archivo; 7.1.3/1 ** identificadores de reservas con el alcance del archivo ** (incluido 'malloc') ** para macros **. – Potatoswatter

+0

Pero #define no declara un identificador con el alcance del archivo, porque no declara un identificador. Debería incorporar 7.1.3/2 en su respuesta cuando la publicó por primera vez y esa es la respuesta real. En particular, cuando leo C89/C90, esta es una discrepancia con respecto al estándar anterior. C99 menciona específicamente el uso de #define, mientras que C89/C90 solo menciona la declaración de un identificador externo, que no es un nombre de macro. De todos modos, menciona 7.1.3/2 como lo hiciste en tu comentario eliminado y aceptaré tu respuesta como correcta. Es 7.1.3/2 que lo hace así. Veo que otra respuesta lo tiene, u1st –

Cuestiones relacionadas