มีวิธีควบคุมลำดับการขยายมาโครหรือไม่

ฉันหวังว่าบางคนอาจมีความคิดเกี่ยวกับวิธีการควบคุม/ระบุลำดับของการขยายมาโคร นี่คือบริบท:


// 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.

จริงๆ แล้วฉันต้องย้ายฮาร์ดแวร์ไปรอบๆ บ้างในช่วงที่ผ่านมา ดังนั้นฉันจึงตัดสินใจจัดกลุ่มข้อมูล LATB ด้วย STATUS_LED อย่างนั้น...


#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 );

แต่อนิจจา LATB,0x0040 ถูกส่งผ่านไปยังอาร์กิวเมนต์ 1 ของมาโคร SET เมื่อไม่ได้ใช้เป็นมาโคร วิธีการนี้จะทำงานได้อย่างถูกต้อง:


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!

แต่น่าเสียดายที่คอมไพเลอร์ของฉันไม่เห็นความจำเป็นในการอินไลน์ฟังก์ชันและทำให้มี 6 คำสั่งในการตั้งค่ารีจิสเตอร์ซึ่งต่างจาก 4 ดังนั้นสำหรับการใช้งานในขณะที่บิตกระแทกจึงเป็นสิ่งที่คาดเดาไม่ได้

ฉันหวังว่าบางคนอาจรู้วิธีขยายมาโคร STATUS_LED ก่อน เช่น: SET( ##STATUS_LED )

ขณะนี้วิธีแก้ปัญหาของฉันในการดำเนินการต่อคือการมีมาโครสองตัว SET และ SETRM (set register, mask) แต่ฉันรู้สึกว่าควรมีวิธีแก้ปัญหาเพราะโค้ดสำหรับ SET ดูเหมือน...


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

และสุดท้าย คอมไพเลอร์ของโปรเซสเซอร์ของฉันไม่รองรับอาร์กิวเมนต์ n ในมาโคร ฉันคิดว่าฉันอาจจะเล่นกับมันได้ แต่อนิจจา :(

ขอบคุณมากที่สละเวลา และขอขอบคุณสำหรับความคิดเห็นใดๆ ฉันสามารถก้าวไปข้างหน้าได้ แต่มันจะสะอาดกว่านี้มากหากฉันสามารถใช้ SET ได้ทุกที่


person daicoden    schedule 04.02.2010    source แหล่งที่มา


คำตอบ (2)


การทดแทนพารามิเตอร์ในการขยายมาโครที่มีลักษณะคล้ายฟังก์ชันเกิดขึ้นในลักษณะที่กำหนด อาร์กิวเมนต์ทั้งหมดที่ไม่ปรากฏหลังตัวดำเนินการ # หรือด้านใดด้านหนึ่งของ ## จะถูกขยายแบบเต็มเมื่อถูกแทนที่ ไม่ใช่ก่อนที่จะขยายแมโครที่คล้ายกับฟังก์ชัน

ซึ่งหมายความว่าเมื่อต้องการทำให้แมโครเดียวกลายเป็นอาร์กิวเมนต์ของแมโครสองตัว การแทนที่แมโครรอบจะต้องเกิดขึ้นก่อนที่จะขยายฟังก์ชันที่ต้องการ เช่น แมโคร

ซึ่งหมายความว่าวิธีแก้ปัญหาของฟังก์ชันที่สอง เช่น มาโครที่ขยายเป็นมาโครที่เหมือนฟังก์ชันที่ต้องการนั้นเป็นวิธีแก้ปัญหาที่ง่ายที่สุด

นั่นคือให้คำจำกัดความ SET ดั้งเดิมของคุณ

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

และมาโครที่ขยายเป็นสองอาร์กิวเมนต์ที่เป็นไปได้

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

คุณต้องใช้แมโครที่คล้ายกับฟังก์ชันอื่นเพื่อรับการทดแทนที่คุณต้องการ

e.g.

#define SET2(x) SET(x)

จากนั้น SET2( STATUS_LED ) จะขยายดังนี้

SET( LATB , 0x0040; )

แล้ว

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

สิ่งนี้ไม่ถูกต้องเนื่องจากมีอาร์กิวเมนต์ไม่เพียงพอสำหรับแมโคร SET พารามิเตอร์จะถูกจับคู่กับอาร์กิวเมนต์ก่อนที่จะมีการขยายอาร์กิวเมนต์ใด ๆ เกิดขึ้น คอมไพเลอร์ของฉันสร้างข้อผิดพลาด ไม่ได้กำหนดพฤติกรรม

SET( STATUS_LED )
person CB Bailey    schedule 04.02.2010

หากชื่อรูทเหมือนกันเสมอคุณสามารถใช้:

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