Dalam buku yang saya baca "Pemrograman C Pendekatan Modern", ada bagian di Halaman 343 yang membahas beberapa trik yang dapat Anda gunakan untuk mengatasi defisit tertentu dalam makro.

Contoh masalah digambarkan sebagai berikut:

#define CONCAT(x,y) x##y (Petunjuk 1)

Penulis kemudian menjelaskan bahwa baris kode berikut akan gagal berfungsi sebagaimana dimaksud jika menggunakan arahan yang disebutkan di atas:

CONCAT(a, CONCAT(b,c)) Baris kode ini akan menghasilkan aCONCAT(b,c) sebagai lawan dari abc yang diinginkan.

Untuk mengatasi kekurangan ini, penulis mengusulkan solusi berikut:

#define CONCAT2(x,y) CONCAT(x,y) (Petunjuk 2)

Penulis menjelaskan bahwa kehadiran Petunjuk 1 dan Petunjuk 2 akan memastikan bahwa baris kode sedikit berbeda CONCAT2(a, CONCAT2(b,c)) diganti dengan benar dengan abc.

(perhatikan bahwa baris kode ini berbeda dari baris kode asli...CONCAT2 digunakan sebagai ganti CONCAT.)

Bisakah seseorang memandu saya melalui mengapa ini akan berhasil mencapai tujuan yang diinginkan? Dari apa yang saya pahami, preprocesser akan terus memindai kode yang telah dikompilasi sampai semua istilah yang ditentukan telah ditangani. Untuk pemindaian tertentu, berapa banyak kata yang ditentukan yang diperbarui per baris?

Saya akan berpikir bahwa aliran penggantian preprocessing berikut terjadi:

Mengingat CONCAT2(a, CONCAT2(b,c))...

Melewati pertama: CONCAT(a, CONCAT2(b,c))

Namun, untuk pelintasan kedua, apakah CONCAT diperluas ke ekspresi daftar penggantinya? Atau apakah CONCAT2 diperluas ke ekspresi daftar penggantinya? Dalam kedua kasus, sepertinya kita sekali lagi sampai pada ekspresi gagal aCONCAT2(b,c) atau CONCAT(a, CONCAT(b,c)), yang oleh karena itu masih akan gagal seperti kasus asli yang kita sajikan.

Bantuan apa pun sangat dihargai!

0
S.Cramer 2 September 2020, 19:53

1 menjawab

Jawaban Terbaik

Saat praprosesor mendeteksi pemanggilan makro seperti fungsi saat memindai baris sumber, praprosesor sepenuhnya memperluas argumen makro sebelum menggantinya ke teks pengganti makro, kecuali di mana argumen muncul sebagai operan dari operator stringifikasi (#) atau penempelan token (##), nilai literalnya digunakan untuk operasi tersebut. Teks pengganti yang dihasilkan, dengan argumen yang diperluas dan hasil dari setiap operasi # dan ## yang diganti, kemudian dipindai ulang untuk makro tambahan untuk diperluas.

Dengan demikian, dengan ...

CONCAT(a, CONCAT(b,c))

... nilai literal dari kedua argumen digunakan sebagai operan untuk operasi penempelan token. Hasilnya adalah ...

aCONCAT(b,c)

. Itu dipindai ulang untuk makro lebih lanjut untuk memperluas, tetapi aCONCAT tidak didefinisikan sebagai nama makro, jadi tidak ada ekspansi makro lebih lanjut terjadi.

Sekarang pertimbangkan...

CONCAT2(a, CONCAT2(b,c))

. Dalam CONCAT2, tidak ada argumen yang merupakan operan # atau ##, jadi keduanya sepenuhnya diperluas secara makro sebelum diganti. Tentu saja a tidak berubah, tetapi CONCAT2(b,c) diperluas ke CONCAT(b,c), yang setelah dipindai ulang diperluas menjadi bc. Dengan mengganti nilai argumen yang diperluas ke dalam teks penggantinya, pemanggilan CONCAT2 luar diperluas menjadi ...

CONCAT(a, bc)

. Perluasan itu kemudian dipindai ulang, dalam konteks teks sumber di sekitarnya, untuk perluasan makro lebih lanjut, menghasilkan ...

abc

. Itu dipindai lagi, tetapi tidak ada ekspansi makro lebih lanjut untuk dilakukan, jadi itulah hasil akhirnya.

1
John Bollinger 2 September 2020, 17:37