Es fácil razonar cómo funcionaría un código así:
#include <string.h>
#define strcmp my_strcmp
int my_strcmp(const char *, const char *)
...
strcmp(str1, str2);
...
Pero la pregunta es si esto es técnicamente correcto o no.
Desde C11:
7.1.3.1 (sobre nombres reservados):
…
- Cada nombre de macro en cualquiera de las siguientes subcláusulas (incluidas las instrucciones futuras de la biblioteca) está reservado para su uso como se especifica si se incluye alguno de sus encabezados asociados; a menos que se indique explícitamente lo contrario (ver 7.1.4).
- Todos los identificadores con enlace externo en cualquiera de las siguientes subcláusulas (incluidas las futuras instrucciones de la biblioteca) y errno siempre se reservan para su uso como identificadores con enlace externo.184)
- Cada identificador con alcance de archivo enumerado en cualquiera de las siguientes subcláusulas (incluidas las futuras instrucciones de la biblioteca) está reservado para su uso como nombre de macro y como identificador con alcance de archivo en el mismo espacio de nombres si se incluye alguno de sus encabezados asociados.
184 La lista de identificadores reservados con enlace externo incluye math_errhandling, setjmp, va_copy y va_end.
Entonces esto significa que strcmp
es una palabra reservada porque string.h
está incluido.
7.1.3.2:
… Si el programa declara o define un identificador en un contexto en el que está reservado (aparte de lo permitido por 7.1.4), o define un identificador reservado como un nombre de macro, el comportamiento es indefinido.
Ahora esto parece decir redefinir strcmp
es un comportamiento indefinido, excepto que de alguna manera está permitido en 7.1.4.
Los contenidos posiblemente relevantes de 7.1.4 son:
7.1.4.1:
… Cualquier función declarada en un encabezado puede implementarse adicionalmente como una macro similar a una función definida en el encabezado, por lo que si una función de biblioteca se declara explícitamente cuando se incluye su encabezado, se puede usar una de las técnicas que se muestran a continuación para garantizar que declaración no se ve afectada por tal macro. Cualquier definición de macro de una función se puede suprimir localmente encerrando el nombre de la función entre paréntesis, porque el nombre no va seguido del paréntesis izquierdo que indica la expansión del nombre de una función de macro. Por la misma razón sintáctica, se permite tomar la dirección de una función de biblioteca incluso si también se define como una macro.185) El uso de #undef para eliminar cualquier definición de macro también garantizará que se haga referencia a una función real. …
185 Esto significa que una implementación proporcionará una función real para cada función de biblioteca, incluso si también proporciona una macro para esa función.
7.1.4.2:
Siempre que una función de biblioteca pueda declararse sin referencia a ningún tipo definido en un encabezado, también está permitido declarar la función y usarla sin incluir su encabezado asociado.
El resto de las cláusulas son irrelevantes. No veo a qué se refiere 7.1.3.2 como “según lo permitido por 7.1.4”, excepto la definición de la función de biblioteca en el mismo encabezado que la función, es decir, el encabezado estándarcomo una macro.
En resumen, ¿el código anterior tiene un comportamiento técnicamente indefinido? Que tal si string.h
no estaba incluido?
Esta pregunta se basa en una premisa falsa. La disputa que surgió aquí no era si la definición de un identificador reservado no estaba definida por C, sino si podía definirse por otros medios y si una persona podía hacerlo (es decir, si, en algunas circunstancias, una persona podía hacer un uso productivo del comportamiento). de una implementación de C que no estaba definida por el estándar de C).
–Eric Postpischil
08/02/2013 a las 16:31