La implementación de GCC de corchetes angulares incluye. ¿Por qué tiene que ser como se describe a continuación?

11

Este documento en su sección 2.6 Computed incluye tiene el siguiente párrafo:

Si la línea se expande a un flujo de tokens que comienza con un token <y que incluye un token>, los tokens entre <y el primero> se combinan para formar el nombre de archivo que se incluirá. Cualquier espacio en blanco entre los tokens se reduce a un solo espacio; entonces se conserva cualquier espacio después del <inicial, pero se ignora un espacio posterior al cierre> . CPP busca el archivo de acuerdo con las reglas para el ángulo incluido.

Sé que esta es una implementación definida, pero ¿por qué tiene que ser así para GCC? Me refiero específicamente a la oración resaltada arriba.

EDITAR

Acabo de notar que el tercer párrafo antes del citado arriba dice lo siguiente:

Debe tener cuidado al definir la macro. #defineguarda tokens, no texto. El preprocesador no tiene forma de saber que la macro se usará como argumento de #include, por lo que genera tokens ordinarios, no un nombre de encabezado. Es poco probable que esto cause problemas si usa comillas dobles, que están lo suficientemente cerca de las constantes de cadena. Sin embargo, si usa corchetes angulares, puede tener problemas .

¿Alguien sabe qué tipo de problema se señala aquí?

Ayrosa
fuente
66
La mejor suposición es que los desarrolladores de GCC piensan que tener espacios al final de un nombre de archivo es una abominación.
user3386109
1
Los nombres de archivo con espacios iniciales y / o finales son muy complicados de usar, especialmente en Windows.
Remy Lebeau
1
El hecho de que se haya definido así no significa necesariamente que deba definirse así. No es obligatorio por el estándar.
Eerorika
Visual Studio elimina el espacio inicial y final, por lo que se comporta de manera diferente. HP aCC se comporta como gcc (quizás por razones de compatibilidad).
Slimak
A veces, la documentación simplemente describe lo que hace el código en lugar de lo contrario, especialmente en casos que no importan (puede usar cualquier espacio en cualquier lugar si usa comillas dobles).
rustyx

Respuestas:

9

Supongo que el implementador eligió la forma más sencilla cuando implementaron esta funcionalidad, sin pensarlo mucho.

Parece que la implementación inicial aterrizó en 2000-07-03 (¡hace dos décadas!). La parte relevante se parece a ( fuente ):

  for (;;)
    {
      t = cpp_get_token (pfile);
      if (t->type == CPP_GREATER || t->type == CPP_EOF)
        break;

      CPP_RESERVE (pfile, TOKEN_LEN (t));
      if (t->flags & PREV_WHITE)
        CPP_PUTC_Q (pfile, ' ');
      pfile->limit = spell_token (pfile, t, pfile->limit);
    }

Notablemente, estalla cuando ve el CPP_GREATERtoken (es decir >), antes de reservar memoria para el token. Esto tiene sentido, ya que no es necesario asignar memoria cuando el token no se escribirá en el búfer.

Luego, solo después de reservar la memoria, el preprocesador verifica si el token tiene un espacio en blanco anterior ( t->flags & PREV_WHITE) y, cuando lo tiene, escribe un carácter de espacio en blanco en el búfer.

Como resultado, en < foo / bar >, solo los espacios en blanco antes foo(es decir, después de la inicial <) /, y barse mantienen.

cpplearner
fuente
Brillante, gran respuesta. Esta es la primera vez que tengo la oportunidad de ver un código en GCC. Gracias por esto.
Ayrosa
Pero, ¿no es cierto que la condición if (t->flags & PREV_WHITE) CPP_PUTC_Q (pfile, ' ');contradice lo que se dice en el documento: "Cualquier espacio en blanco entre los tokens se reduce a un solo espacio; ..."?
Ayrosa