Termasuk satu file sumber C yang lain?

111

Apakah OK (atau bahkan dianjurkan / praktek yang baik) untuk #includesebuah .cfile dalam lain .cberkas?

SS Anne
sumber
4
Saya mengambil kebebasan untuk mengedit pertanyaan, dan juga menerapkan beberapa tag praktis. Beberapa tag saya mungkin menunjukkan bias, heh.
bersantai

Jawaban:

113

Jika digunakan dengan benar, ini bisa menjadi teknik yang berguna.

Katakanlah Anda memiliki subsistem yang kompleks dan berperforma penting dengan antarmuka publik yang cukup kecil dan banyak kode implementasi yang tidak dapat digunakan kembali. Kode berjalan ke beberapa ribu baris, seratus atau lebih fungsi pribadi dan cukup banyak data pribadi. Jika Anda bekerja dengan sistem tertanam non-sepele, Anda mungkin berurusan dengan situasi ini cukup sering.

Solusi Anda mungkin akan berlapis, modular, dan dipisahkan dan aspek-aspek ini dapat direpresentasikan dan diperkuat secara berguna dengan mengkodekan berbagai bagian subsistem dalam file yang berbeda.

Dengan C, Anda bisa kehilangan banyak dengan melakukan ini. Hampir semua rantai alat memberikan pengoptimalan yang layak untuk satu unit kompilasi, tetapi sangat pesimis tentang apa pun yang dinyatakan eksternal.

Jika Anda memasukkan semuanya ke dalam satu modul sumber C, Anda mendapatkan -

  • Peningkatan kinerja & ukuran kode - pemanggilan fungsi akan menjadi sebaris dalam banyak kasus. Bahkan tanpa sebaris, kompilator memiliki peluang untuk menghasilkan kode yang lebih efisien.

  • Tautkan data level & fungsi menyembunyikan.

  • Menghindari polusi namespace dan akibatnya - Anda dapat menggunakan nama yang tidak terlalu berat.

  • Kompilasi & tautan lebih cepat.

Tetapi Anda juga mendapatkan kekacauan yang tidak suci saat mengedit file ini dan Anda kehilangan modularitas yang tersirat. Ini dapat diatasi dengan memecah sumber menjadi beberapa file dan memasukkannya ke dalam satu unit kompilasi.

Anda perlu menerapkan beberapa konvensi untuk mengelola ini dengan benar. Ini akan bergantung pada toolchain Anda sampai batas tertentu, tetapi beberapa petunjuk umum adalah -

  • Letakkan antarmuka publik dalam file header terpisah - Anda tetap harus melakukan ini.

  • Memiliki satu file .c utama yang menyertakan semua file .c anak perusahaan. Ini juga bisa termasuk kode untuk antarmuka publik.

  • Gunakan pelindung kompilator untuk memastikan bahwa header pribadi dan modul sumber tidak disertakan oleh unit kompilasi eksternal.

  • Semua data & fungsi pribadi harus dinyatakan statis.

  • Pertahankan perbedaan konseptual antara file .c dan .h. Ini memanfaatkan konvensi yang ada. Perbedaannya adalah Anda akan memiliki banyak deklarasi statis di header Anda.

  • Jika toolchain Anda tidak memaksakan alasan apa pun untuk tidak melakukannya, beri nama file implementasi privat sebagai .c dan .h. Jika Anda menggunakan include guard, ini tidak akan menghasilkan kode dan tidak memperkenalkan nama baru (Anda mungkin akan mendapatkan beberapa segmen kosong selama penautan). Keuntungan besar adalah bahwa alat lain (misalnya IDE) akan memperlakukan file-file ini dengan tepat.


sumber
1
+1 ini masih menjadi kenyataan, sementara penyusun yang lebih baik akan membuat metode ini usang seiring waktu. GCC 4.5 dengan pengoptimalan waktu tautan merupakan langkah besar dalam prosesnya.
u0b34a0f6ae
Saya telah melihat begitu banyak program yang melakukan ini, dan itu membuat saya jengkel ketika saya mencoba menggunakan kembali kode mereka. Terima kasih telah menjelaskan mengapa mereka melakukannya, dan menyarankan penggunaan penjaga (yang sering tidak dilakukan).
Joey Adams
Dalam pengembangan tertanam untuk C51, penggunaan file C eksternal & multipel tidak menyebabkan apa-apa selain sakit kepala. Saya beralih ke memiliki satu file C termasuk semua yang lain untuk mendapatkan kembali waktu saya.
mahesh
Untuk catatan: GCC mendukung pengoptimalan di seluruh unit terjemahan yang berbeda, lihat utas SO ini dan bagian manual GCC tentang pengoptimalan waktu tautan .
Twonky
60

apakah itu baik-baik saja ya, itu akan dikompilasi

apakah itu direkomendasikan? tidak ada - .c file dikompilasi ke file .obj, yang dihubungkan bersama setelah kompilasi (oleh linker) ke dalam executable (atau pustaka), jadi tidak perlu menyertakan satu file .c di file lain. Yang mungkin ingin Anda lakukan adalah membuat file .h yang mencantumkan fungsi / variabel yang tersedia di file .c lainnya, dan menyertakan file .h

Steven A. Lowe
sumber
14
Juga perlu diperhatikan bahwa bahkan jika dikompilasi, itu mungkin tidak menautkan jika file #included .c juga dikompilasi dan dua file objek ditautkan bersama - Anda bisa berakhir dengan simbol yang didefinisikan banyak.
Nick Meyer
1
Sebuah pertanyaan kecil. Saya memiliki file header yang mendeklarasikan metode struct + dan juga file .c yang sesuai untuk mendefinisikannya. Jika metode itu mengambil struct sebagai parameter, bagaimana saya menghindari menyertakan file .c di file .c lain di mana metode utama didefinisikan?
stdout
12

Tidak.

Bergantung pada lingkungan build Anda (Anda tidak menentukannya), Anda mungkin mendapati bahwa itu berfungsi persis seperti yang Anda inginkan.

Namun, ada banyak lingkungan (baik IDE dan banyak Makefile buatan tangan) yang mengharapkan untuk mengkompilasi * .c - jika itu terjadi, Anda mungkin akan berakhir dengan kesalahan linker karena simbol duplikat.

Biasanya, praktik ini harus dihindari.

Jika Anda benar-benar harus #memasukkan sumber (dan umumnya harus dihindari), gunakan sufiks file yang berbeda untuk file tersebut.

Andrew Edgecombe
sumber
9

Saya pikir saya akan berbagi situasi di mana tim saya memutuskan untuk menyertakan file .c. Arsitektur kami sebagian besar terdiri dari modul yang dipisahkan melalui sistem pesan. Penangan pesan ini bersifat publik, dan memanggil banyak fungsi pekerja statis lokal untuk melakukan pekerjaannya. Masalah muncul saat mencoba mendapatkan cakupan untuk kasus pengujian unit kami, karena satu-satunya cara untuk menggunakan kode implementasi pribadi ini secara tidak langsung melalui antarmuka pesan publik. Dengan beberapa fungsi pekerja setinggi lutut di tumpukan, ini ternyata menjadi mimpi buruk untuk mencapai cakupan yang tepat.

Menyertakan file .c memberi kami cara untuk mencapai roda penggerak di mesin yang menarik kami uji.

Matthew Alford
sumber
6

Anda dapat menggunakan kompiler gcc di linux untuk menghubungkan dua file c dalam satu output. Misalkan Anda memiliki dua file c, satu adalah 'main.c' dan yang lainnya adalah 'support.c'. Jadi perintah untuk menghubungkan keduanya adalah

gcc main.c support.c -o main.out

Dengan dua file ini akan dihubungkan ke satu output main.out Untuk menjalankan output perintahnya

./main.out

Jika Anda menggunakan fungsi di main.c yang dideklarasikan di file support.c maka Anda harus mendeklarasikannya di main juga menggunakan kelas penyimpanan eksternal.

sumitroy
sumber
5

Ekstensi file tidak menjadi masalah bagi kebanyakan kompiler C, jadi itu akan berhasil.

Namun, bergantung pada makefile atau pengaturan proyek Anda, file c yang disertakan mungkin menghasilkan file objek terpisah. Saat menautkan itu mungkin mengarah ke simbol yang ditentukan ganda.

HS.
sumber
3

Anda dapat menyertakan file .C atau .CPP dengan benar ke dalam file sumber lainnya. Bergantung pada IDE Anda, Anda biasanya dapat mencegah tautan ganda dengan melihat properti file sumber yang ingin Anda sertakan, biasanya dengan mengklik kanan padanya dan mengklik properti, dan hapus centang / centang kompilasi / tautan / kecualikan dari build atau opsi apa pun itu. mungkin. Atau Anda tidak dapat menyertakan file dalam proyek itu sendiri, sehingga IDE tidak akan tahu bahwa file itu ada dan tidak akan mencoba untuk mengkompilasinya. Dan dengan makefiles Anda tidak akan memasukkan file ke dalamnya untuk kompilasi dan penautan.

EDIT: Maaf saya membuatnya sebagai jawaban, bukan balasan ke jawaban lain :(

MikeyPro
sumber
1

Bahasa C tidak melarang #include semacam itu, tetapi unit terjemahan yang dihasilkan masih harus C.

Saya tidak tahu program apa yang Anda gunakan dengan file .prj. Jika Anda menggunakan sesuatu seperti "make" atau Visual Studio atau apa pun, pastikan Anda menyetel daftar file untuk dikompilasi tanpa salah satu yang tidak dapat dikompilasi secara independen.

Pemrogram Windows
sumber
0

Memasukkan file C ke dalam file lain adalah legal, tetapi bukan hal yang disarankan untuk dilakukan, kecuali Anda tahu persis mengapa Anda melakukan ini dan apa yang ingin Anda capai.
Saya hampir yakin bahwa jika Anda akan memposting di sini alasan bahwa di balik pertanyaan Anda, komunitas akan menemukan cara lain yang lebih tepat untuk mencapai tujuan Anda (harap perhatikan "hampir", karena mungkin ini adalah solusi yang diberikan konteksnya ).

Omong-omong, saya melewatkan bagian kedua dari pertanyaan itu. Jika file C disertakan ke file lain dan dalam waktu yang sama disertakan ke proyek, Anda mungkin akan mengalami masalah simbol duplikat mengapa menghubungkan objek, yaitu fungsi yang sama akan didefinisikan dua kali (kecuali semuanya statis).

Ilya
sumber
-6

Anda harus menambahkan header seperti ini

#include <another.c>

catatan: kedua file harus ditempatkan di tempat yang sama

saya menggunakan ini di codevison AVR untuk pengontrol mikro ATMEGA dan bekerja dengan benar tetapi tidak berfungsi dalam file bahasa C normal

milad
sumber