tour plusplus plus oficial documentacion c++ c++11 language-lawyer c++14

plusplus - c++ website



¿Es definitivamente ilegal referirse a un nombre reservado? (6)

En la lista de propuestas estándar, 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, a los efectos de esta pregunta, por qué se dio ese código y por qué se escribió de esa manera (ya que hubo una buena razón, pero aquí es irrelevante). Supone que _ALGORITHM es un protector de encabezado dentro del encabezado estándar <algorithm> tal como se entrega con alguna implementación de biblioteca estándar conocida. No hay intención inherente de portabilidad aquí.

Ahora, _ALGORITHM por supuesto sería 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 usarán de otra manera; no se requiere diagnóstico

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

  • Cada nombre que contiene un doble guión bajo _ _ o comienza con un guión bajo seguido de una letra mayúscula (2.12) está reservado a la implementación para cualquier uso.
  • Cada nombre que comienza con un guión bajo está reservado a la implementación para su uso como un 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 definan / muten / no definan los nombres que caen bajo los criterios anteriores, para que los implementadores de la biblioteca estándar puedan usar dichos nombres sin temor a conflictos con el código del cliente.

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

Un razonamiento práctico dado fue que la macro _ALGORITHM podría expandirse a algún código que borra su disco duro, por ejemplo. Sin embargo, teniendo en cuenta la probable intención de la regla, diría que tal eventualidad tiene más que ver con la naturaleza obvia definida por la implementación * del nombre de _ALGORITHM , y menos con que sea totalmente ilegal referirse a ella .

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

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

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

#ifdef __cplusplus extern "C" { #endif

y nunca he escuchado una queja sobre eso.

¿Entonces, qué piensas? ¿"No se usará de otra manera" incluye simplemente escribir tal nombre? ¿O es probable que no sea tan estricto (lo que puede indicar una oportunidad para ajustar la redacción estándar)?


Históricamente, el propósito de hacer uso de tales tokens "comportamiento indefinido" es que los compiladores tienen la libertad de adjuntar cualquier significado que deseen a cualquier token que no esté definido dentro del estándar C. Por ejemplo, en algunos procesadores integrados, el uso de __xdata como clase de almacenamiento para una variable pedirá que se almacene en un área de RAM a la que el acceso es más lento que el área de almacenamiento de variables normal, pero es mucho más grande. En los procesadores típicos de esa familia, el almacenamiento para las variables "normales" se limitaría 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 acerca de lo que los compiladores pueden hacer con tales directivas, aunque normalmente (no estoy seguro de si el estándar exige este comportamiento, aunque no conozco que los compiladores lo violen) tales tokens generalmente se ignoran dentro del código que es deshabilitado utilizando un #if o directivas similares.

Algunos archivos de encabezado de las bibliotecas iniciarán sus propios identificadores internos con algo que comienza con dos guiones bajos pero incluye un patrón que probablemente no utilizará un compilador para ningún propósito (por ejemplo, la versión 23 de la biblioteca Foozle podría preceder a sus identificadores con el uso __FZ23 ). Sería perfectamente legítimo que los futuros compiladores usen identificadores que comiencen con __FZ23 para otros fines, y si eso sucediera, la biblioteca Foozle tendría que cambiarse para usar otra cosa. Sin embargo, si es probable que una actualización importante del compilador requiera la reescritura de la biblioteca Foozle por otras razones, 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 proyectos 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

Cuando se escribe un código nuevo, el último patrón suele ser mejor, pero el patrón anterior a veces puede ser útil cuando se adapta el código existente escrito en una plataforma que requiere __XDATA para que se pueda usar tanto en plataformas que usan / requieren esa directiva como en plataformas que no haga.


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 usar esos nombres como se documenta. Esto se usa a menudo para extensiones como __builtin_expect , donde el proveedor del compilador evita cualquier conflicto con sus identificadores (que están declarados por su código) usando esos nombres reservados. Incluso el estándar los usa para cosas como __attribute__ para asegurarse de que no rompa el código existente (legal) al agregar nuevas funciones.


Los nombres en [cpp.predefined] son ​​diferentes. Esos 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 portátil bien definido. Usar un identificador específico de la implementación como el ejemplo de _ALGORITHM está mal formado porque viola una regla de regla.

Sí, soy plenamente consciente de los múltiples ejemplos en los que la especificación de la biblioteca utiliza "debe" significar que "este es un requisito en el código de usuario, y las violaciones son UB, no mal formadas".

En cuanto a si es UB o definida por la implementación, ejecutar un programa mal formado da como resultado UB. La redacción estándar dice claramente que el programa está mal formado, UB ocurre si la implementación aún elige aceptar el programa y ejecutarlo.

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

Si los usuarios están preocupados por la falta de formación y el posible UB, y dichos usuarios quieren escribir C ++ portátil, no deben usar identificadores reservados en programas portátiles de C ++. Si los usuarios aceptan que, independientemente del estándar que prohíba dicho uso, ninguna implementación práctica borrará su disco duro, pueden usar libremente dichos identificadores reservados, pero según la letra del estándar, dichos usos aún están mal formados.


Que sea 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 idioma. Cuando usa un nombre que está reservado para la implementación, el comportamiento de su programa no está definido. Eso significa que la definición de idioma no le dice qué hace el programa. Nada más y 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 en los encabezados y adivina qué significan varios identificadores no documentados puede ser que pueda usarlos, pero no se sorprenda si su código se rompe cuando una actualización posterior cambia algo.

No te __cplusplus en __cplusplus . Es el lenguaje central, y el contenido de los guiones bajos, etc. es la biblioteca. Si eso no es convincente, considérelo un problema técnico. Puedes usar __cplusplus en programas de C ++; Su significado está bien definido.


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

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

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


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

Cada identificador que contiene un subrayado doble __ o comienza con un guión bajo seguido de una letra mayúscula se reserva a la implementación para cualquier uso.

Cualquier uso . (un texto similar ocurre antes y después de que se aplique la corrección del defecto)

__cplusplus está definido por el estándar. _ALGORITHM está reservado por el estándar para ser utilizado por las implementaciones. Estas parecen bastante diferentes? (Las dos secciones de la norma están en conflicto, ya que una establece que __cplusplus está reservada para cualquier uso, y otra la usa específicamente, pero creo que el ganador de ese conflicto está claro).

El identificador de _ALGORITHM podría, bajo la norma, ser usado como parte de un paso de preprocesamiento para decir "reemplazar este código fuente con un código de borrado del disco duro". Su existencia (antes del preprocesamiento o después) podría ser suficiente para cambiar completamente el comportamiento de su programa.

Ahora esto es poco probable, pero no creo que resulte en una implementación no conforme. Es solo una cuestión de calidad de implementación.

Una implementación es libre de documentar y definir lo que significa _ALGORITHM . 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 implementación actual de <algorithm> como documentación probablemente llegará muy lejos.

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