Apakah ada cara untuk mengontrol urutan ekspansi makro

Saya berharap seseorang memiliki ide tentang cara mengontrol/menentukan urutan ekspansi makro. Inilah konteksnya:


// 32 bit increments, processor has registers for set, clear and invert
#define CLR_OFF 1
#define SET_OFF 2
#define INV_OFF 3


#define SET(reg,bits) *((volatile unsigned long*)(& reg+SET_OFF)) = bits
//Now if I use this I can do it quite nicely with
#define STATUS_LED 0x0040;
SET(LATB, STATUS_LED); // LATB is port of the LED.

Saya sebenarnya harus memindahkan perangkat keras akhir-akhir ini, jadi saya memutuskan untuk mengelompokkan info LATB dengan STATUS_LED seperti ini...


#define STATUS_LED_PORT LATB
#define STATUS_LED_MASK 0x0040;
#define STATUS_LED STATUS_LED_PORT, STATUS_LED_MASK

//And I try to use it via
SET( STATUS_LED );

Namun sayang, LATB,0x0040 diteruskan ke argumen 1 makro SET. Jika tidak digunakan sebagai makro, metode ini berfungsi dengan baik:


inline void SET(u32_t *reg, u32_t bits) { ((volatile u32_t *) (((u32_t)reg) + SET_OFF*4 )) = bits; }
//Change the STATUS_LED macro to
#define STATUS_LED &STATUS_LED_PORT, STATUS_LED_MASK
SET( STATUS_LED); //Works great!

Namun sayangnya kompiler saya tidak melihat perlunya memasukkan fungsi dan menyebabkan 6 instruksi mengatur register dibandingkan dengan 4, jadi untuk digunakan saat bit-banging tidak dapat diprediksi.

Saya berharap seseorang mengetahui cara untuk memperluas makro STATUS_LED terlebih dahulu, seperti: SET( ##STATUS_LED )

Saat ini solusi saya untuk melanjutkan adalah memiliki dua makro SET, dan SETRM (set register, mask) tetapi saya rasa harus ada solusi karena kode untuk SET terlihat seperti...


#define SETRM(reg,bits) ...
#define SET(args) SETRM(args) //WHY WOULD THIS GET EXPANDED HERE??

Dan terakhir, kompiler prosesor saya tidak mendukung n-argumen ke makro, saya pikir saya mungkin bisa memainkannya tetapi sayangnya :(.

Terima kasih banyak atas waktu Anda, dan saya akan menghargai pemikiran apa pun, saya dapat melanjutkan, tetapi akan jauh lebih bersih jika saya dapat menggunakan SET di mana saja.


person daicoden    schedule 04.02.2010    source sumber


Jawaban (2)


Pergantian parameter dalam perluasan makro mirip fungsi terjadi dengan cara tertentu. Semua argumen yang tidak muncul setelah operator # atau kedua sisi ## diperluas sepenuhnya secara makro saat diganti, bukan sebelum makro seperti fungsi diperluas.

Artinya, untuk menjadikan satu makro menjadi dua argumen makro, putaran substitusi makro harus terjadi sebelum fungsi yang diperlukan seperti makro itu sendiri diperluas.

Artinya solusi fungsi kedua seperti makro yang diperluas ke makro mirip fungsi yang diinginkan adalah solusi paling sederhana.

yaitu berdasarkan definisi SET asli Anda

#define SET(reg,bits) *((volatile unsigned long*)(& reg+SET_OFF)) = bits

dan makro yang diperluas menjadi dua argumen potensial

#define STATUS_LED_PORT LATB
#define STATUS_LED_MASK 0x0040;
#define STATUS_LED STATUS_LED_PORT, STATUS_LED_MASK

Anda harus menggunakan makro mirip fungsi lain untuk mendapatkan substitusi yang Anda perlukan.

e.g.

#define SET2(x) SET(x)

Kemudian SET2( STATUS_LED ) diperluas sebagai berikut.

SET( LATB , 0x0040; )

Kemudian

*((volatile unsigned long*)(& LATB + 2 )) = 0x0040;

Ini tidak valid karena argumen pada makro SET tidak cukup; parameternya dicocokkan dengan argumen sebelum perluasan argumen terjadi. Kompiler saya menghasilkan kesalahan; perilakunya tidak ditentukan.

SET( STATUS_LED )
person CB Bailey    schedule 04.02.2010

Jika nama root selalu sama, Anda dapat menggunakan:

#define SET_COMPOSITE(root) SET(root##_PORT, root##_MASK)
person ntd    schedule 04.02.2010