GCC'nin köşeli parantez uygulaması içerir. Neden aşağıda açıklandığı gibi olmalıdır?


11

2.6 Bilgisayarlı İçindekiler bölümündeki bu belge aşağıdaki paragrafa sahiptir:

Çizgi, bir <belirteciyle başlayan ve bir> belirtecini içeren bir belirteç akışına genişlerse, eklenecek dosya adını oluşturmak için <ve ilk> arasındaki belirteçler birleştirilir. Jetonlar arasındaki boşluklar tek bir alana indirgenir; ilk <boşluktan sonraki herhangi bir boşluk korunur, ancak kapanmadan önceki boşluk> yok sayılır . CPP, köşeli ayraç içeren kurallara göre dosyayı arar.

Bunun uygulama tanımlı olduğunu biliyorum, ama neden GCC için bu şekilde olması gerekiyor? Özellikle vurgulanan cümleye atıfta bulunuyorum.

DÜZENLE

Yukarıda belirtilen paragraftan önceki üçüncü paragrafın şunları söylediğini fark ettim:

Makroyu tanımlarken dikkatli olmalısınız. #definemetin değil jeton kaydeder. Önişlemcinin makronun argüman olarak kullanılacağını bilmesinin bir yolu yoktur #include, bu nedenle başlık adı değil sıradan jetonlar üretir. Bu, dize sabitlerine yeterince yakın olan çift tırnak işareti içerirse sorun yaratmaz. Ancak köşeli parantez kullanırsanız, sorun yaşayabilirsiniz .

Burada ne tür bir sorun olduğuna dikkat çeken var mı?


6
En iyi tahmin, GCC'nin geliştiricilerinin bir dosya adının sonunda boşluklara sahip olmanın bir iğrençlik olduğunu düşünmesidir.
user3386109

1
Önde gelen ve / veya sondaki boşluklara sahip dosya adları, özellikle Windows'da, uyandırmak için çok titizdir.
Remy Lebeau

1
Bunun böyle tanımlanmış olması, mutlaka böyle tanımlanması gerektiği anlamına gelmez. Standart tarafından zorunlu kılınmamıştır.
eerorika

Visual Studio hem başlangıç ​​hem de bitiş alanını kaldırır, bu nedenle farklı davranır. HP aCC, gcc gibi davranır (belki de uyumluluk nedeniyle).
Slimak

Bazen dokümantasyon, özellikle önemli olmayan durumlarda (çift tırnak kullanırsanız herhangi bir yerde herhangi bir alanı kullanabilirsiniz), kodun tersi olmak yerine ne yapacağını açıklar.
rustyx

Yanıtlar:


8

Sanırım uygulayıcı, bu işlevselliği uygularken, çok fazla düşünmeden en basit yolu seçti.

İlk uygulamanın 2000-07-03 (yirmi yıl önce!) İlgili bölüm ( kaynak ) aşağıdaki gibi görünür :

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

Özellikle, CPP_GREATERjeton için bellek ayırmadan önce jetonu gördüğünde (yani >) kırılır . Belirteç arabelleğe yazılmayacakken bellek ayırmaya gerek olmadığından bu mantıklıdır.

Ardından, yalnızca bellek ayrıldıktan sonra önişlemci, belirtecin önünde boşluk olup olmadığını kontrol eder ( t->flags & PREV_WHITEve), ara belleğe bir boşluk karakteri yazar.

Sonuç olarak, < foo / bar >sadece önceki boşluklar foo(yani, başlangıçtan sonra <) /, ve bartutulur.


Harika, harika bir cevap. Bu ilk kez GCC'de bir kod parçası görme fırsatı buldum. Bunun için teşekkür ederim.
Ayrosa

Ancak durum if (t->flags & PREV_WHITE) CPP_PUTC_Q (pfile, ' ');, belgede söylenenle çelişiyor değil mi : "Simgeler arasında herhangi bir boşluk tek bir alana indirgeniyor; ..."?
Ayrosa
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.