Mengapa kompiler tidak dapat menghindari mengimpor file header dua kali dengan sendirinya?

13

Baru mengenal C ++! Jadi saya membaca ini: http://www.learncpp.com/cpp-tutorial/110-a-first-look-at-the-preprocessor/

Pelindung kepala

Karena file header dapat menyertakan file header lainnya, dimungkinkan untuk berakhir dalam situasi di mana file header dimasukkan beberapa kali.

Jadi kami membuat arahan preprosesor untuk menghindari ini. Tapi saya tidak yakin - mengapa kompilator tidak bisa ... tidak mengimpor hal yang sama dua kali?

Mengingat bahwa pelindung tajuk adalah opsional (tetapi tampaknya praktik yang baik), hampir membuat saya berpikir bahwa ada skenario ketika Anda ingin mengimpor sesuatu dua kali. Meskipun saya tidak bisa memikirkan skenario seperti itu sama sekali. Ada ide?

Akhir
sumber
Pada kompiler MS ada #pragma onceyang memberitahu kompiler untuk hanya memasukkan file itu sekali.
CodesInChaos

Jawaban:

27

Mereka bisa, seperti yang ditunjukkan oleh bahasa baru yang melakukannya.

Tetapi keputusan desain dibuat bertahun-tahun yang lalu (ketika kompiler C adalah beberapa tahap independen) dan sekarang untuk menjaga kompatibilitas pra-prosesor harus bertindak dengan cara tertentu untuk memastikan kompilasi kode lama seperti yang diharapkan.

Sebagai C ++ mewarisi cara memproses file header dari C itu mempertahankan teknik yang sama. Kami mendukung keputusan desain lama. Tetapi mengubah cara kerjanya terlalu berisiko, banyak kode yang berpotensi rusak. Jadi sekarang kita harus mengajari pengguna baru bahasa bagaimana cara menggunakan termasuk penjaga.

Ada beberapa trik dengan file header yang sengaja Anda sertakan beberapa kali (ini sebenarnya menyediakan fitur yang bermanfaat). Meskipun jika kita mendesain ulang paradigma dari awal kita bisa menjadikan ini cara non-default untuk memasukkan file.

Martin York
sumber
7

Sebaliknya tidak akan seekspresif, mengingat bahwa mereka memilih untuk mempertahankan kompatibilitas dengan C dan dengan demikian melanjutkan dengan preprosesor daripada sistem pengemasan tradisional.

Satu hal yang terlintas dalam pikiran saya adalah saya memiliki proyek yang merupakan API. Saya punya dua file header x86lib.hdan x86lib_internal.h. Karena internal sangat besar, saya memisahkan bit "publik" ke x86lib.h sehingga pengguna tidak perlu menyisihkan waktu ekstra untuk kompilasi.

Ini memperkenalkan masalah lucu dengan dependensi jadi saya akhirnya memiliki aliran yang berjalan seperti ini di x86lib_internal

  1. Atur INTERNAL preprocessor define
  2. Sertakan x86lib.h (yang pintar bertindak dengan cara tertentu ketika internal didefinisikan)
  3. Lakukan beberapa hal dan perkenalkan beberapa hal yang digunakan di x86lib.h
  4. Setel SETELAH preprosesor tentukan
  5. Sertakan x86lib.h lagi (kali ini ia akan mengabaikan segalanya kecuali untuk bagian SETELAH terpisah yang bergantung pada elemen x86lib_internal

Saya tidak akan mengatakan itu adalah cara terbaik untuk melakukannya, tetapi itu mencapai apa yang saya inginkan.

Earlz
sumber
0

Salah satu kesulitan dengan pengecualian duplikat-header otomatis adalah bahwa standar C relatif diam pada subjek apa yang termasuk nama file. Sebagai contoh, misalkan file utama yang dikompilasi berisi arahan #include "f1.h"dan #include "f2.h", dan file yang ditemukan untuk arahan keduanya mengandung #include "f3.h". Jika f1.hdan f2.hberada di direktori yang berbeda, tetapi ditemukan dengan mencari path termasuk, maka akan menjadi tidak jelas #includearahan dalam file tersebut dimaksudkan untuk memuat f3.hfile yang sama , atau yang berbeda.

Hal-hal menjadi lebih buruk jika seseorang menambahkan kemungkinan menyertakan file termasuk jalur relatif. Dalam beberapa kasus di mana file header menggunakan jalur relatif untuk arahan termasuk bersarang, dan di mana orang ingin menghindari membuat perubahan pada file header yang disediakan, mungkin perlu memiliki file header yang digandakan di beberapa tempat dalam struktur direktori proyek. Meskipun ada beberapa salinan fisik dari file header itu, mereka harus dianggap semantik seolah-olah mereka adalah file tunggal.

Jika #pragma oncedirektif memungkinkan pengidentifikasi untuk mengikuti once, dengan semantik bahwa kompiler harus melewatkan file jika pengidentifikasi cocok dengan satu dari #pragma oncedirektif yang ditemui sebelumnya , maka semantik akan jelas; sebuah kompiler yang dapat memberi tahu bahwa suatu #includearahan akan memuat #pragma oncefile bertanda sama dengan yang sebelumnya, itu dapat menghemat sedikit waktu dengan melewatkan file tanpa membukanya lagi, tetapi deteksi tersebut tidak secara semantik penting karena file akan dilewati apakah atau tidak nama file dikenali sebagai kecocokan. Saya tidak mengetahui adanya kompiler yang bekerja seperti itu. Memiliki kompiler mengamati apakah file cocok dengan pola #ifndef someIdentifier / #define someIdentifier / #endif [for that ifndef] / nothing followingdan memperlakukan hal seperti itu setara dengan #pragma once someIdentifierjika di atassomeIdentifier tetap didefinisikan, pada dasarnya sama baiknya.

supercat
sumber