Apakah mungkin, menggunakan preprocessor C / C ++, untuk menghitung baris dalam file sumber, menjadi makro atau semacam kompilasi-nilai waktu yang tersedia? Misalnya saya bisa mengganti MAGIC1
, MAGIC2
dan MAGIC3
berikut ini, dan mendapatkan nilai 4 entah bagaimana saat menggunakan MAGIC3
?
MAGIC1 // can be placed wherever you like before the relevant
// lines - either right before them, or in global scope etc.
foo(); MAGIC2
bar(); MAGIC2
baz(); MAGIC2
quux(); MAGIC2
// ... possibly a bunch of code here; not guaranteed to be in same scope ...
MAGIC3
Catatan:
- Ekstensi khusus kompiler untuk kemampuan preprosesor dapat diterima tetapi tidak diinginkan.
- Jika ini hanya mungkin dengan bantuan beberapa C ++, sebagai lawan C, konstruk, itu juga dapat diterima tetapi tidak diinginkan (yaitu saya ingin sesuatu yang akan bekerja untuk C).
- Jelas ini dapat dilakukan dengan menjalankan file sumber melalui beberapa skrip prosesor eksternal, tapi bukan itu yang saya tanyakan.
c++
c-preprocessor
einpoklum
sumber
sumber
__LINE__
yang mewakili nomor baris saat ini__COUNTER__
dan / atauBOOST_PP_COUNTER
?int arr[MAGIC4]
dan mendapatkan jumlah baris di beberapa bagian kode saya yang sebelumnya dihitung.Jawaban:
Ada
__LINE__
makro preprocessor yang memberi Anda bilangan bulat untuk garis muncul. Anda bisa mengambil nilainya pada beberapa baris, lalu beberapa baris berikutnya, dan membandingkan.Jika Anda ingin menghitung kemunculan sesuatu daripada garis sumber,
__COUNTER__
mungkin merupakan opsi non-standar, yang didukung oleh beberapa kompiler seperti GCC dan MSVC.Saya mengambil nilai awal
__COUNTER__
karena mungkin telah digunakan sebelumnya di file sumber, atau beberapa header yang disertakan.Dalam C daripada C ++ ada batasan pada variabel konstan, jadi
enum
bisa digunakan sebagai gantinya.Mengganti const dengan
enum
:sumber
__COUNTER__
bukan standar dalam C atau C ++. Jika Anda tahu itu bekerja dengan kompiler tertentu, tentukan mereka.BEFORE
danAFTER
bukan makroSaya tahu bahwa permintaan OP adalah untuk menggunakan makro, tapi saya ingin menambahkan cara lain untuk melakukan ini yang tidak melibatkan penggunaan makro.
C ++ 20 memperkenalkan
source_location
kelas yang mewakili informasi tertentu tentang kode sumber, seperti nama file, nomor baris, dan nama fungsi. Kita bisa menggunakannya dengan mudah dalam hal ini.Dan contoh hidup di sini .
sumber
source_location
menjadi eksperimental di C ++ 20?source_location
sekarang secara resmi bagian dari C ++ 20. Periksa di sini . Saya tidak bisa menemukan versi kompiler gcc di godbolt.org yang sudah mendukungnya dalam arti non eksperimental. Bisakah Anda jelaskan sedikit lebih banyak pernyataan Anda - Saya hanya bisa menggunakan jumlah baris dalam cakupan yang sama dengan baris yang saya hitung ?line_number_start
danline_number_end
dalam lingkup itu, di tempat lain. Jika saya menginginkannya di tempat lain, saya harus meneruskannya pada saat run-time - yang mengalahkan tujuannya.line_number_end
terlihat pada waktu kompilasi di luar cakupannya. Koreksi saya jika saya salah.Untuk kelengkapan: Jika Anda ingin menambahkan
MAGIC2
setelah setiap baris, Anda dapat menggunakan__COUNTER__
:https://godbolt.org/z/i8fDLx (pengembalian
3
)Anda dapat membuatnya dapat digunakan kembali dengan menyimpan nilai awal dan akhir
__COUNTER__
.Secara keseluruhan ini sangat rumit sekalipun. Anda juga tidak akan dapat menghitung baris yang berisi arahan preprosesor atau diakhiri dengan
//
komentar. Saya akan menggunakan__LINE__
sebagai gantinya, lihat jawaban lainnya.sumber
static_assert
?__COUNTER__
masih nol pada awalnya sebagai header lain, dll. Mungkin menggunakannya.__COUNTER__
dua kali dan mengambil perbedaan__COUNTER__
sendiri tidak akan diizinkan, dan perlu diperluas ke sesuatu atau tidak akan dihitung (Saya tidak dapat mengingat aturan 100% tentang ini).Solusi yang agak lebih kuat, memungkinkan untuk penghitung yang berbeda (asalkan mereka tidak mencampurkan, dan tidak ada gunanya
__COUNTER__
untuk tugas lain):Ini menyembunyikan detail implementasi (meskipun menyembunyikannya di dalam makro ...). Ini adalah generalisasi jawaban @ MaxLanghof. Perhatikan bahwa
__COUNTER__
mungkin memiliki nilai bukan nol saat kita memulai penghitungan.Begini cara menggunakannya:
Juga, ini valid C - jika preprosesor Anda mendukung
__COUNTER__
, yaitu.Bekerja pada GodBolt .
Jika Anda menggunakan C ++, Anda dapat memodifikasi solusi ini untuk tidak mencemari namespace global - dengan menempatkan penghitung di dalamnya
namespace macro_based_line_counts { ... }
, ataunamespace detail
dll.)sumber
Berdasarkan komentar Anda, jika Anda ingin menentukan ukuran array (waktu kompilasi) dalam C atau C ++, Anda bisa melakukannya
Jika Anda memerlukan
sizeof(array)
di baris intervening, Anda dapat menggantinya dengan referensi variabel statis (kecuali jika benar-benar harus berupa ekspresi konstanta bilangan bulat) dan kompiler pengoptimalisasi harus memperlakukannya sama saja (menghilangkan kebutuhan variabel statis untuk ditempatkan) dalam kenangan)Sebuah
__COUNTER__
solusi berbasis (jika ekstensi yang tersedia) sebagai lawan dari__LINE__
satu berbasis akan bekerja sama.constexpr
s di C ++ harus bekerja dengan baikenum
, tetapienum
akan bekerja di plain C juga (solusi saya di atas adalah solusi C polos).sumber
__COUNTER__
Solusi berbasis memiliki masalah juga: Anda lebih baik berharap makro ajaib Anda adalah satu-satunya pengguna__COUNTER__
, setidaknya sebelum Anda selesai menggunakan__COUNTER__
. Masalahnya pada dasarnya semua bermuara pada fakta-fakta sederhana yang__COUNTER__/__LINE__
merupakan fitur preprocessor dan preprocessor bekerja dalam satu pass, sehingga Anda tidak dapat melakukan backpatch ekspresi konstanta integer nanti berdasarkan pada__COUNTER__
/__LINE__
. Satu-satunya cara (dalam C setidaknya) adalah untuk menghindari kebutuhan di tempat pertama, misalnya, dengan menggunakan deklarasi array maju tanpa ukuran (deklarasi array diketik tidak lengkap).\
tidak mempengaruhi__LINE__
- jika ada jeda baris,__LINE__
meningkat. Contoh 1 , contoh 2 .