Implementacja nawiasów kątowych przez GCC obejmuje. Dlaczego musi być tak, jak opisano poniżej?

11

Ten dokument w sekcji 2.6 „Obliczone obejmuje” zawiera następujący akapit:

Jeśli linia zostanie rozwinięta do strumienia tokena rozpoczynającego się od <tokena i zawierającego token>, wówczas tokeny między <a pierwszym> są łączone w celu utworzenia nazwy pliku, która ma zostać uwzględniona. Każda biała spacja między tokenami jest zredukowana do pojedynczej spacji; następnie dowolne spacja po początkowym <zostaje zachowane, ale końcowe spacja przed zamknięciem> jest ignorowane . CPP wyszukuje plik zgodnie z zasadami obejmującymi nawiasy kątowe.

Wiem, że to jest implementacja zdefiniowana, ale dlaczego tak musi być dla GCC? Mam na myśli szczególnie podkreślone zdanie powyżej.

EDYTOWAĆ

Właśnie zauważyłem, że trzeci akapit przed cytowanym powyżej mówi:

Podczas definiowania makra należy zachować ostrożność. #definezapisuje tokeny, a nie tekst. Preprocesor nie może wiedzieć, że makro zostanie użyte jako argument #include, więc generuje zwykłe tokeny, a nie nazwę nagłówka. Jest mało prawdopodobne, aby powodowało to problemy, jeśli użyjesz cudzysłowów zawierających, które są wystarczająco zbliżone do stałych ciągów. Jeśli jednak użyjesz nawiasów kątowych, możesz mieć problemy .

Czy ktoś wie, jakie problemy są tutaj wskazywane?

Ayrosa
źródło
6
Można przypuszczać, że twórcy GCC uważają, że spacje na końcu nazwy pliku są obrzydliwością.
user3386109
1
Nazwy plików z wiodącymi i / lub końcowymi spacjami są bardzo wybredne, szczególnie w systemie Windows.
Remy Lebeau
1
To, że zostało tak zdefiniowane, niekoniecznie oznacza, że ​​musi być tak zdefiniowane. Nie jest to wymagane przez standard.
eerorika
Visual Studio usuwa zarówno początkową, jak i końcową przestrzeń, więc zachowuje się inaczej. HP aCC zachowuje się jak gcc (być może ze względu na kompatybilność).
Slimak
Czasami dokumentacja po prostu opisuje, co dzieje się z kodem zamiast na odwrót, szczególnie w przypadkach, które nie mają znaczenia (możesz użyć dowolnego miejsca w dowolnym miejscu, jeśli użyjesz podwójnych cudzysłowów).
rustyx

Odpowiedzi:

8

Wydaje mi się, że implementator wybrał najprostszy sposób, kiedy wdrożył tę funkcjonalność, nie zastanawiając się długo.

Wydaje się, że pierwsze wdrożenie wylądowało w 2000-07-03 (dwie dekady temu!). Odpowiednia część wygląda ( źródło ):

  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);
    }

W szczególności wybucha, gdy widzi CPP_GREATERtoken (tj. >), Zanim zarezerwuje pamięć dla tokena. Ma to sens, ponieważ nie trzeba przydzielać pamięci, gdy token nie zostanie zapisany w buforze.

Następnie dopiero po zarezerwowaniu pamięci preprocesor sprawdza, czy token ma poprzednią spację ( t->flags & PREV_WHITE), a kiedy to robi, zapisuje znak bufora w buforze.

W rezultacie, w < foo / bar >, tylko białe spacje przed foo(to znaczy po początkowym <) /i barsą zachowywane.

cpplearner
źródło
Świetna, świetna odpowiedź. Po raz pierwszy mam okazję zobaczyć fragment kodu w GCC. Dziękuję Ci za to.
Ayrosa
Ale czy nie jest tak, że warunek jest if (t->flags & PREV_WHITE) CPP_PUTC_Q (pfile, ' ');sprzeczny z tym, co zostało powiedziane w dokumencie: „Jakakolwiek biała spacja między tokenami jest zredukowana do pojedynczej spacji; ...”?
Ayrosa