Implementasi GCC sudut-kurung termasuk. Mengapa harus seperti yang dijelaskan di bawah ini?

11

Dokumen ini di bagian 2.6 Termasuk Dihitung memiliki paragraf berikut:

Jika garis meluas ke aliran token yang dimulai dengan token <, dan termasuk token>, maka token antara <dan yang pertama> digabungkan untuk membentuk nama file yang akan disertakan. Setiap spasi putih antara token dikurangi menjadi satu ruang; maka setiap ruang setelah inisial <dipertahankan, tetapi ruang trailing sebelum penutupan> diabaikan . CPP mencari file sesuai dengan aturan untuk angle-bracket termasuk.

Saya tahu ini adalah implementasi yang didefinisikan, tetapi mengapa harus seperti ini untuk GCC? Saya merujuk secara khusus pada kalimat yang disorot di atas.

EDIT

Saya baru saja memperhatikan bahwa paragraf ketiga sebelum yang dikutip di atas mengatakan sebagai berikut:

Anda harus berhati-hati saat mendefinisikan makro. #definemenyimpan token, bukan teks. Preprosesor tidak memiliki cara untuk mengetahui bahwa makro akan digunakan sebagai argumen #include, sehingga menghasilkan token biasa, bukan nama header. Ini tidak akan menimbulkan masalah jika Anda menggunakan double-quote include, yang cukup dekat dengan konstanta string. Namun, jika Anda menggunakan kurung sudut, Anda mungkin mengalami masalah .

Adakah yang tahu masalah apa yang ditunjukkan di sini?

Ayrosa
sumber
6
Tebakan terbaik adalah bahwa pengembang GCC berpikir bahwa memiliki spasi di akhir nama file adalah kekejian.
user3386109
1
Nama file dengan spasi terdepan dan / atau trailing sangat rumit untuk digunakan, terutama pada Windows.
Remy Lebeau
1
Hanya karena sudah didefinisikan seperti itu, tidak harus berarti harus didefinisikan seperti itu. Itu tidak diamanatkan oleh standar.
eerorika
Visual Studio menghilangkan ruang awal dan akhir, sehingga berperilaku berbeda. HP aCC berperilaku seperti gcc (mungkin karena alasan kompatibilitas).
Slimak
Kadang-kadang dokumentasi hanya menjelaskan apa yang dilakukan kode daripada sebaliknya, terutama dalam kasus yang tidak masalah (Anda dapat menggunakan ruang apa pun di mana saja jika Anda menggunakan tanda kutip ganda).
rustyx

Jawaban:

9

Saya kira implementor memilih cara paling sederhana ketika mereka mengimplementasikan fungsi ini, tanpa terlalu memikirkannya.

Tampaknya implementasi awal mendarat pada 2000-07-03 (dua dekade lalu!). Bagian yang relevan seperti ( sumber ):

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

Khususnya, itu pecah ketika melihat CPP_GREATERtoken (yaitu >), sebelum menyimpan memori untuk token. Ini masuk akal, karena tidak perlu mengalokasikan memori ketika token tidak akan ditulis ke buffer.

Kemudian, hanya setelah memori dicadangkan, preprocessor memeriksa apakah token telah mendahului spasi putih ( t->flags & PREV_WHITE) dan ketika itu terjadi, menulis karakter spasi putih ke buffer.

Akibatnya, dalam < foo / bar >, hanya spasi putih sebelum foo(yaitu, setelah awal <) /, dan bardisimpan.

cpplearner
sumber
Cemerlang, jawaban yang bagus. Ini adalah pertama kalinya saya berkesempatan melihat sepotong kode di GCC. Terima kasih untuk ini.
Ayrosa
Tapi bukankah itu kasus yang if (t->flags & PREV_WHITE) CPP_PUTC_Q (pfile, ' ');bertentangan dengan apa yang dikatakan dalam dokumen: "Setiap spasi putih antara token dikurangi menjadi satu ruang; ..."?
Ayrosa