¿Es definitivamente ilegal referirse a un nombre reservado?


En la lista std-proposals, se dio el siguiente código:

#include <vector>
#include <algorithm>

void foo(const std::vector<int> &v) {
#ifndef _ALGORITHM
  std::for_each(v.begin(), v.end(), [](int i){std::cout << i; }
#endif
}

Ignoremos, para los propósitos de esta pregunta, por qué se dio ese código y por qué se escribió de esa manera (ya que había una buena razón, pero es irrelevante aquí). Supone que _ALGORITHM es un protector de encabezado dentro del encabezado estándar <algorithm> como se incluye con alguna implementación de biblioteca estándar conocida. No hay intención inherente de portabilidad aquí.

Ahora, _ALGORITHM, por supuesto ser un nombre reservado, por:

[C++11: 2.11/3]: Además, algunos identificadores están reservados para su uso por implementaciones de C++ y bibliotecas estándar (17.6.4.3.2) y no se utilizarán de otro modo; no se requiere diagnóstico.

[C++11: 17.6.4.3.2/1]: Ciertos conjuntos de nombres y firmas de función siempre están reservados a la implementación:

  • Cada nombre que contiene un doble guion bajo _ _ o comienza con un guion bajo seguido de una letra mayúscula (2.12) está reservado al implementación para cualquier uso.
  • Cada nombre que comienza con un guion bajo está reservado a la implementación para su uso como nombre en el espacio de nombres global.

Siempre tuve la impresión de que la intención de este pasaje era evitar que los programadores definieran/mutando/undefining nombres que caen bajo los criterios anteriores, para que los implementadores de bibliotecas estándar puedan usar tales nombres sin ningún temor de conflictos con el cliente codificar.

Pero, en la lista std-proposals, se afirmó que este código está mal formado por referirse simplemente a un nombre reservado. Ahora puedo ver cómo el uso de la frase "no se utilizará de otra manera" de [C++11: 2.11/3]: puede sugerir eso.

Una justificación práctica dada fue que la macro _ALGORITHM podría expandirse a algún código que limpie su disco duro, por ejemplo. Sin embargo, teniendo en cuenta la intención probable de la regla, diría que tal eventualidad tiene más que ver con la obvia naturaleza * definida por la implementación del nombre _ALGORITHM, y menos que ver con que es totalmente ilegal referirse a él.

* "definición de implementación" en su sentido del idioma inglés, no en el sentido estándar de C++ de la frase

Yo diría que, siempre y cuando estemos contentos de que vamos a tener resultados definidos por la implementación y que deberíamos investigar qué significa esa macro en nuestra implementación (si es que existe!), no debe ser inherentemente ilegal referirse a tal macro siempre que no intentemos modificarlo.

Por ejemplo, código como el siguiente se usa en todo el lugar para distinguir entre código compilado como C y código compilado como C++:

#ifdef __cplusplus
extern "C" {
#endif

Y nunca he oído una queja sobre eso.

Entonces, ¿qué piensas? ¿"no se utilizará de otra manera" incluye simplemente escribir tal nombre? O probablemente no pretende ser tan estricto (lo que puede apuntar a una oportunidad para ajustar la redacción estándar)?

Author: Lightness Races in Orbit, 2015-04-30

6 answers

Si es legal o no es específico de la implementación (y específico del identificador).

Cuando el Estándar otorga a la implementación el derecho exclusivo de usar estos nombres, eso incluye el derecho de hacer que los nombres estén disponibles en código de usuario. Si una implementación lo hace, genial.

Pero si una implementación no le da expresamente el derecho, está claro de "no se utilizará de otra manera" que el Estándar no lo hace, y usted tiene un comportamiento indefinido.

 18
Author: Ben Voigt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-30 15:34:12

La parte importante es "reservada a la implementación". Significa que el proveedor del compilador puede usar esos nombres e incluso documentarlos. Su código puede entonces usar esos nombres como está documentado. Esto se usa a menudo para extensiones como __builtin_expect, donde el proveedor del compilador evita cualquier choque con sus identificadores (que son declarados por su código) mediante el uso de esos nombres reservados. Incluso el estándar los usa para cosas como __attribute__ para asegurarse de que no rompa el código (legal) existente cuando adición de nuevas características.

 17
Author: Daniel Frey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-30 15:35:10

Http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1882

Cada identificador que contiene un doble valor secundario __ o comienza con un guion bajo seguido de una letra mayúscula está reservado a la implementación para cualquier uso.

cualquier uso. (texto similar ocurre tanto antes como después de que se aplique la corrección de defectos)

__cplusplus está definido por el estándar. _ALGORITHM está reservado por el estándar para ser utilizado por las implementaciones. Estos parece bastante diferente? (Las dos secciones de la norma entran en conflicto, en que uno afirma que __cplusplus está reservado para cualquier uso, y otro lo usa específicamente, pero creo que el ganador de ese conflicto está claro).

El identificador _ALGORITHM podría, bajo el estándar, usarse como parte de un paso de preprocesamiento para decir "reemplazar este código fuente con código de eliminación de disco duro". Su existencia (antes del pre-procesamiento, o después) podría ser suficiente para cambiar completamente su programa comportamiento.

Ahora bien, esto es poco probable, pero no creo que resulte en una implementación no conforme. Se trata únicamente de la calidad de la aplicación.

Una implementación es libre de documentar y definir lo que _ALGORITHM significa. Por ejemplo, podría documentar que es un protector de encabezado para <algorithm>, e indica si ese archivo de encabezado se ha incluido. Tratar su actual implementación <algorithm> como documentación probablemente vaya muy lejos.

Supongo que usar __cplusplus en modo C es técnicamente "tan malo" como usar _ALGORITHM, pero esta pregunta es una pregunta c++, no una pregunta c. No he profundizado en el estándar c para buscar citas al respecto.

 4
Author: Yakk - Adam Nevraumont,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-30 15:48:05

Los nombres en [cpp.predefinidos] son diferentes. Estos tienen un significado específico, por lo que una implementación no puede reservarlos para ningún uso, y usarlos en un programa tiene un significado portable bien definido. El uso de un identificador específico de la implementación como el ejemplo de _ALGORITHM está mal formado porque viola una regla de shall.

Sí, soy plenamente consciente de varios ejemplos donde la especificación de la biblioteca utiliza "shall" para significar " este es un requisito en el código de usuario, y las violaciones son UB, no mal formado".

En cuanto a si es UB o definido por la implementación, ejecutar un programa mal formado resulta en UB. La redacción estándar dice claramente que el programa está mal formado, UB ocurre si la implementación todavía elige aceptar el programa y ejecutarlo.

Entonces, si un programa usa el identificador _ALGORITHM, ese programa está mal formado, y ejecutar tal programa es UB, pero eso no significa que no funcione bien en una implementación que usa _ALGORITHM como un protector de inclusión, ni ¿significa que no funciona bien en una implementación que no lo hace.

Si los usuarios están preocupados por tal mala forma y potencial UB, y dichos usuarios quieren escribir portable C++, no deben usar identificadores reservados en programas portable C++. Si los usuarios aceptan que, independientemente de la norma que prohíbe tal uso, ninguna implementación práctica borrará su disco duro, pueden usar libremente dichos identificadores reservados, pero según la letra de la norma, dichos usos siguen siendo mal formado.

 4
Author: Ville Voutilainen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-30 20:40:50

Históricamente, el propósito de hacer el uso de tales tokens "comportamiento indefinido" es que los compiladores son libres de adjuntar cualquier significado que quieran a cualquier token que no esté definido dentro del estándar C. Por ejemplo, en algunos procesadores embebidos, usar _ _ xdata como una clase de almacenamiento para una variable pedirá que se almacene en un área de RAM que es más lenta de acceder que el área normal de almacenamiento de variables, pero es mucho más grande. En procesadores típicos de esa familia, almacenamiento para " normal" las variables se limitarían a unos 100 bytes, pero el almacenamiento para las variables xdata puede ser mucho mayor. hasta 64K.El estándar básicamente no dice nada sobre lo que los compiladores pueden hacer con tales directivas, aunque normalmente (no estoy seguro de si el estándar exige este comportamiento, aunque no estoy consciente de que los compiladores lo violen) estos tokens generalmente se ignoran dentro del código que está deshabilitado usando #if o directivas similares.

Algunos archivos de cabecera de bibliotecas iniciarán sus propios archivos internos identificadores con algo que comienza con dos guiones bajos pero incluye un patrón que es poco probable que sea utilizado por un compilador para cualquier propósito(por ejemplo, la versión 23 de la biblioteca Foozle podría preceder a sus identificadores con use __FZ23). Sería perfectamente legítimo para un futuro compilador usar identificadores comenzando con _ _ FZ23 para otros propósitos, y si eso sucediera la biblioteca Foozle necesitaría ser cambiada para usar otra cosa. Si, sin embargo, es probable que una actualización importante del compilador probablemente requeriría reescrituras de la biblioteca Foozle por otras razones de todos modos, ese riesgo puede ser aceptable en comparación con el riesgo de que los identificadores entren en conflicto con el código externo.

Tenga en cuenta también que algunos archivos de encabezado de proyecto que están dirigidos a un procesador que requiere directivas __ pueden definir condicionalmente macros con esos nombres cuando se compilan para otros procesadores, por ejemplo:

#ifndef USE_XDATA
#define __XDATA
#endif

Aunque un patrón algo mejor sería generalmente:

#ifdef USE_XDATA
#define XDATA __XDATA
#else
#define XDATA
#endif

Al escribir código nuevo, el último patrón es a menudo mejor, pero el primer patrón a veces puede ser útil cuando se adapta el código existente escrito en una plataforma que requiere _ _ XDATA para que pueda ser utilizado tanto en plataformas que usan/requieren esa directiva como en plataformas que no lo hacen.

 2
Author: supercat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-30 16:33:23

Si es legal o no es una cuestión de derecho local. Si significa algo, y si es así, qué, es un asunto para la definición del lenguaje. Cuando se utiliza un nombre que está reservado a la implementación, el comportamiento de su programa es indefinido. Eso significa que la definición del lenguaje no le dice lo que hace el programa. Nada más, nada menos. Si el compilador que está utilizando documenta lo que hace un identificador reservado en particular, entonces puede usar ese identificador con ese compilador. Si busca entre los encabezados y adivina qué significan varios identificadores no documentados que podrías usar, pero no te sorprendas si tu código se rompe cuando una actualización posterior cambia algo.

No te quedes colgado en __cplusplus. Es el lenguaje central, y las cosas sobre guiones bajos dobles, etc. es biblioteca. Si eso no es convincente, considéralo un fallo. Puede usar __cplusplus en programas C++; su significado está bien definido.

 0
Author: Pete Becker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-30 18:58:42