#define STR1 "s"
#define STR2 "1"
#define STR3 STR1 ## STR2
เป็นไปได้หรือไม่ที่จะเชื่อมต่อกันโดยมี STR3 == "s1" คุณสามารถทำได้โดยส่ง args ไปยังฟังก์ชัน Macro อื่น แต่มีทางตรงไหม?
#define STR1 "s"
#define STR2 "1"
#define STR3 STR1 ## STR2
เป็นไปได้หรือไม่ที่จะเชื่อมต่อกันโดยมี STR3 == "s1" คุณสามารถทำได้โดยส่ง args ไปยังฟังก์ชัน Macro อื่น แต่มีทางตรงไหม?
คำตอบ:
หากเป็นทั้งสองสตริงคุณสามารถทำได้:
#define STR3 STR1 STR2
ตัวประมวลผลก่อนเชื่อมต่อสตริงที่อยู่ติดกันโดยอัตโนมัติ
แก้ไข:
ดังที่ระบุไว้ด้านล่างไม่ใช่ตัวประมวลผลก่อน แต่เป็นคอมไพเลอร์ที่ทำการเชื่อมต่อ
L"a"
และ"b"
จะได้รับL"ab"
แต่คุณสามารถเชื่อมL"a"
และที่จะได้รับL"b"
L"ab"
คุณไม่จำเป็นต้องใช้โซลูชันประเภทนั้นสำหรับสตริงลิเทอรัลเนื่องจากมีการเชื่อมต่อกันที่ระดับภาษาและจะใช้ไม่ได้อยู่ดีเนื่องจาก "s" "1" ไม่ใช่โทเค็นตัวประมวลผลล่วงหน้าที่ถูกต้อง
[แก้ไข: เพื่อตอบสนองต่อความคิดเห็น "Just for the record" ที่ไม่ถูกต้องด้านล่างซึ่งน่าเสียดายที่ได้รับการโหวตหลายครั้งฉันจะย้ำข้อความข้างต้นและสังเกตว่าส่วนของโปรแกรม
#define PPCAT_NX(A, B) A ## B
PPCAT_NX("s", "1")
สร้างข้อความแสดงข้อผิดพลาดนี้จากขั้นตอนก่อนการประมวลผลของ gcc: ข้อผิดพลาด: การวาง "" s "" และ "" 1 "" ไม่ได้ให้โทเค็นการประมวลผลล่วงหน้าที่ถูกต้อง
]
อย่างไรก็ตามสำหรับการวางโทเค็นทั่วไปให้ลองทำดังนี้:
/*
* Concatenate preprocessor tokens A and B without expanding macro definitions
* (however, if invoked from a macro, macro arguments are expanded).
*/
#define PPCAT_NX(A, B) A ## B
/*
* Concatenate preprocessor tokens A and B after macro-expanding them.
*/
#define PPCAT(A, B) PPCAT_NX(A, B)
จากนั้นเช่นทั้งสองPPCAT_NX(s, 1)
และPPCAT(s, 1)
ผลิตระบุs1
เว้นแต่s
ถูกกำหนดให้เป็นมาโครซึ่งในกรณีที่ผลิตPPCAT(s, 1)
<macro value of s>1
การดำเนินการต่อในธีมคือมาโครเหล่านี้:
/*
* Turn A into a string literal without expanding macro definitions
* (however, if invoked from a macro, macro arguments are expanded).
*/
#define STRINGIZE_NX(A) #A
/*
* Turn A into a string literal after macro-expanding it.
*/
#define STRINGIZE(A) STRINGIZE_NX(A)
จากนั้น
#define T1 s
#define T2 1
STRINGIZE(PPCAT(T1, T2)) // produces "s1"
ตรงกันข้าม,
STRINGIZE(PPCAT_NX(T1, T2)) // produces "T1T2"
STRINGIZE_NX(PPCAT_NX(T1, T2)) // produces "PPCAT_NX(T1, T2)"
#define T1T2 visit the zoo
STRINGIZE(PPCAT_NX(T1, T2)) // produces "visit the zoo"
STRINGIZE_NX(PPCAT(T1, T2)) // produces "PPCAT(T1, T2)"
"s""1"
ใช้ได้ใน C (และ C ++) เป็นโทเค็นสองโทเค็น (ตัวอักษรสตริง) ที่คอมไพเลอร์จะเชื่อมต่อตัวเองและคุกคามเป็นโทเค็นเดียว
"s""1" isn't a valid token
- ถูกต้อง; มันเป็นอย่างที่คุณพูดสองโทเค็น แต่การยึดเข้าด้วยกันด้วย ## จะทำให้โทเค็นเป็นโทเค็นก่อนการประมวลผลเดียวไม่ใช่สองโทเค็นดังนั้นคอมไพเลอร์จะไม่ทำการเชื่อมต่อกัน แต่ตัวอักษรจะปฏิเสธ (ภาษาต้องมีการวินิจฉัย)
STRINGIZE_NX(whatever occurs here)
ขยายเป็น "อะไรก็ตามที่เกิดขึ้นที่นี่" โดยไม่คำนึงถึงคำจำกัดความมาโครสำหรับสิ่งใดก็ตามเกิดขึ้นหรือที่นี่
if A is defined as FRED then STRINGIZE_NX(A) still expands to "FRED"
- นั่นเป็นเท็จและไม่เหมือนกับการทดสอบของคุณ คุณกำลังพยายามอย่างยิ่งที่จะไม่เข้าใจหรือทำให้ถูกต้องและฉันจะไม่ตอบกลับคุณต่อไป
คำแนะนำ: STRINGIZE
มาโครด้านบนนั้นยอดเยี่ยม แต่ถ้าคุณทำผิดพลาดและอาร์กิวเมนต์ไม่ใช่มาโคร - คุณพิมพ์ชื่อผิดหรือลืม#include
ไฟล์ส่วนหัวจากนั้นคอมไพเลอร์จะใส่ชื่อมาโครที่อ้างว่ามีความสุขลงใน สตริงที่ไม่มีข้อผิดพลาด
หากคุณตั้งใจให้อาร์กิวเมนต์STRINGIZE
เป็นมาโครที่มีค่า C ปกติเสมอ
#define STRINGIZE(A) ((A),STRINGIZE_NX(A))
จะขยายอีกครั้งและตรวจสอบความถูกต้องทิ้งสิ่งนั้นแล้วขยายอีกครั้งเป็นสตริง
มันเอาฉันในขณะที่จะคิดออกว่าทำไมSTRINGIZE(ENOENT)
กำลังจะจบสิ้นขึ้นเป็น"ENOENT"
แทน"2"
... errno.h
ผมไม่ได้รวม
,
ดำเนินการอย่างเหมาะสม :)
((1),"1") "." ((2),"2")
แทนที่จะเป็น "1" "." "2")
STRINGIZE
คำจำกัดความดั้งเดิมใช้"The value of ENOENT is " STRINGIZE(ENOENT)
งานได้ในขณะที่"The value of ENOENT is" STRINGIZE_EXPR(X)
เกิดข้อผิดพลาด