¿Es un comportamiento indefinido redefinir un nombre estándar?

9 minutos de lectura

¿Es un comportamiento indefinido redefinir un nombre estandar
Shahbaz

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

1647717132 55 ¿Es un comportamiento indefinido redefinir un nombre estandar
steve jesop

Al menos una de las razones por las que es UB es que string.h puede introducir macros. Por razones de implementación interna, esas macros podrían haberse escrito asumiendo que strcmp es la función strcmp “real”. si defines strcmp ser otra cosa y luego usar esas macros, strcmp se expandirá a my_strcmp en las macros, con consecuencias inesperadas.

En lugar de tratar de averiguar exactamente qué código estaría bien en el ... y lo que no, la norma pone un alto anticipado a tus travesuras.

También tenga en cuenta que, aparte del hecho de que el estándar lo prohíbe rotundamente, su #define strcmp my_strcmp podría ser una redefinición de macro, porque string.h se permite hacer #define strcmp __strcmp o lo que sea. Entonces, en algunas implementaciones conformes, su código está mal formado.

  • Eso fue lo que pensé yo también. Que tal si string.h es no ¿incluido?

    – Shahbaz

    8 de febrero de 2013 a las 12:21

  • @Shahbaz: strcmp es un caso un poco especial porque está cubierto por los nombres reservados para direcciones futuras (cualquier cosa que comience con str), por lo que creo que probablemente esté reservado si incluye ninguna encabezado estándar. Sin embargo, en general, en C, si no incluye un encabezado estándar, los nombres que define no se reservan como macros/identificadores, pero aún están reservados para enlaces externos. Hay algunos nombres que el estándar dice que están definidos por más de un encabezado.

    –Steve Jessop

    8 de febrero de 2013 a las 12:49


  • Derecha. Gracias por la respuesta. Había dicho que es un comportamiento indefinido en una respuesta mía, pero a otros no les pareció claro. Pregunté para asegurarme.

    – Shahbaz

    8 de febrero de 2013 a las 13:07

  • @Shahbaz: Eric tiene razón en que el hecho de que algo sea UB no significa “no puedes hacerlo”. Significa que el estándar no le da a su programa un derecho inalienable para hacerlo. No estaba diciendo que no es un comportamiento indefinido, estaba diciendo que no es necesariamente cierto que no puedes hacerlo. Si está escribiendo código portátil, equivale a lo mismo, no querrá hacer nada que solo ciertas implementaciones garanticen que funcionará. Si está escribiendo código no portátil, la documentación de su sistema es tan válida como la estándar.

    –Steve Jessop

    8 de febrero de 2013 a las 13:10


1647717132 985 ¿Es un comportamiento indefinido redefinir un nombre estandar
Eric Pospischil

Un programa que declara o define identificadores reservados no es estrictamente conforme (C 2011 4 5) pero puede serlo (C 2011 4 7).

La disputa de la que surgió esta pregunta no era sobre si declarar o definir un identificador reservado es un comportamiento que no está definido por C, sino si el comportamiento puede definirse por otros medios, como la documentación para una implementación específica de C, y si un autor del programa podría hacerlo.

Algunas personas tratan el “comportamiento indefinido” como si significara “No puedes hacer esto”. Esta es una interpretación incorrecta de “comportamiento indefinido”. El comportamiento indefinido no es algo que el estándar requiera que evites; es algo con lo que el estándar C no te ayuda.

El estándar C establece explícitamente que impone sin requisitos en un comportamiento indefinido. En particular, esto significa que no hay ningún requisito de que no pueda hacerlo y ningún requisito de que otra especificación no defina el comportamiento. Casi todos los programas prácticos utilizan un comportamiento que el estándar C no define, cuando realiza llamadas al sistema definidas por la documentación del sistema operativo o llamadas a la biblioteca definidas por la documentación de la biblioteca o se basa en los formatos de tipos de datos definidos por la implementación específica de C para la que está diseñado. por.

En C, el “comportamiento indefinido” es simplemente el final de las reglas establecidas por el estándar C. Es un campo abierto por el que puedes navegar por otros medios y no un muro que bloquea tu progreso.

  • El Estándar C tampoco impone ningún juicio sobre si las implementaciones de calidad destinadas a varios propósitos deberían definir varios comportamientos más allá de los exigidos por el estándar, ni si una implementación puede ser adecuada para un propósito particular [or any purpose whatsoever] sin hacerlo Por ejemplo, una implementación de baja calidad pero conforme podría imponer un límite en la cantidad de veces que aparece la letra “i” en un texto fuente y comportarse de manera esencialmente arbitraria si un programa excede ese límite. Una implementación de muy baja calidad podría establecer ese límite tan bajo como 0…

    – Super gato

    3 de agosto de 2018 a las 19:15

  • …si la forma en que se comporta cuando se excede ese límite coincidiría con el comportamiento de algún programa inventado particular que ejerce todos los límites en la sección de Límites de traducción del Estándar. Después de todo, alimentar el último “Programa Único” en la implementación produciría un comportamiento indistinguible de “procesarlo” de manera conforme. Por supuesto, las implementaciones de calidad no deberían hacer eso, pero el punto es que el estándar no intenta prohibir todas las formas en que la implementación de baja calidad podría volverse inútil (o menos útil de lo que podría ser).

    – Super gato

    3 de agosto de 2018 a las 19:23

Sí, es un comportamiento indefinido. Es PROBABLE que funcione, pero no puedes estar seguro.

Creo que la razón de esto es permitir que el compilador tenga un conocimiento integrado de cómo str funcionan las funciones. Y por supuesto, strcmp ya puede ser una macro de memcmp(s1, s2, strlen(s1)) o algo así [I’m not saying that’s how it is, just that COULD be.

I don’t believe “not including string.h” actually helps.

I would suggest that you do a search and replace of strcmp with my_strcmp in the source. You can always go the other way around and use #define my_strcmp(s1, s2) strcmp(s1, s2) should you wish to “go back”.

  • It’s not my code. I answered to another question that this is undefined behavior, and I was met with resistance. That’s why asked to make sure.

    – Shahbaz

    Feb 8, 2013 at 12:22

  • Ok, so you may want to advice that “doing it the other way around” will work!

    – Mats Petersson

    Feb 8, 2013 at 12:23

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad