มาโคร C - ไดนามิก #include

ฉันกำลังพยายามหาวิธีสร้างสตริงตัวแปรสำหรับคำสั่ง #include โดยใช้ GCC

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

การสร้างไฟล์นี้ไม่ใช่ปัญหา รวมไปถึงที่น่าเสียดายก็คือ

สิ่งที่ฉันมีจนถึงตอนนี้คือ (identities.h):

// identities.h

# define PASTER2(str)  #str
# define PASTER(str)   PASTER2(str ## .iden)
# define EVALUATOR(x)  PASTER(x)

# define IDENTITIES_FILE EVALUATOR(__FILE__)
# include IDENTITIES_FILE

ตามหลักการแล้ว จะใช้เช่นนี้ (main.c):

//main.c

# include "identities.h"

int main() {return 0;}

ซึ่งจะถูกขยายในการส่งผ่านครั้งเดียวโดยตัวประมวลผลล่วงหน้าก่อนการคอมไพล์เพื่อให้ได้ผลลัพธ์:

//main.c (preprocessed)

# include "main.c.iden"

int main() {return 0;}

การอ้อมสองระดับที่ฉันใช้ (PASTER และ EVALUATOR) เป็นผลมาจาก สิ่งนี้ โพสต์

ขออภัย สิ่งนี้ใช้งานไม่ได้ และฉันยังเหลือข้อผิดพลาด:

obj/win32/dbg/main.o
In file included from main.c:1:0:
identities.h:42:1: error: #include expects "FILENAME" or <FILENAME>

ฉันคิดว่าปัญหาคือคำสั่ง include ไม่มีเครื่องหมายคำพูด .. มีความคิดเห็นใดบ้าง


person J T    schedule 03.05.2011    source แหล่งที่มา
comment
หากคุณมีซอร์ส C ที่สร้างขึ้นแบบไดนามิก คุณสามารถสร้างไฟล์ส่วนหัวใหม่ของไฟล์ส่วนหัวทั้งหมดที่คุณต้องการรวมแบบไดนามิกได้หรือไม่ แม้ว่าฉันยังอยากรู้ว่าเป็นไปได้ไหมที่จะทำสิ่งที่คุณต้องการจะทำ   -  person leetNightshade    schedule 03.05.2011
comment
คำตอบสั้นๆ: คุณไม่สามารถทำเช่นนี้ได้   -  person Alexandre C.    schedule 03.05.2011
comment
@leet: ไม่ ปัญหาต้องใช้แนวทางที่เรียบง่ายที่สุดในการปรับเปลี่ยนระบบบิลด์ปัจจุบัน มีการตกลงกันว่าเราจะพยายามทำเช่นนี้ โดยการแก้ไขแต่ละไฟล์เพื่อรวม identities.h ส่วนหัวทั่วไปเพียงไฟล์เดียว และมีเพียงไฟล์เดียวเท่านั้น   -  person J T    schedule 03.05.2011
comment
@AlexandreC. แปลกดี ผมทำได้ ฉันจะต้องไม่มีอยู่ในจักรวาลของคุณ ;-) ฉันคิดว่าคุณหมายความว่าคุณไม่สามารถทำเช่นนี้ด้วย มาตรฐาน C/C++   -  person artless noise    schedule 13.12.2013


คำตอบ (5)


แล้ว BOOST_PP_STRINGIZE จาก ไลบรารี Boost Preprocessor ล่ะ จัดทำขึ้นเป็นพิเศษเพื่อเพิ่มเครื่องหมายคำพูดรอบชื่อ

person Mikael Persson    schedule 03.05.2011
comment
น่าเสียดายที่ทั้งหมดนี้เพิ่มอีกหนึ่งปอนด์ก่อนข้อความ: # Defin BOOST_PP_STRINGIZE_I(text) #text - person J T; 03.05.2011
comment
BOOST_PP_STRINGIZE ไม่เพียงเพิ่ม # ปอนด์เท่านั้น เอกสารระบุโดยเฉพาะว่าแทนที่จะใช้เพียง # มาโครนี้อนุญาตให้ขยายอาร์กิวเมนต์ได้จริง (และ # ไม่ได้ทำ) หลังจากการทดสอบไม่กี่ครั้ง ดูเหมือนว่าปัญหาหลักของคุณคือ FILE ขยายเป็นชื่อไฟล์ที่อยู่ระหว่างเครื่องหมายคำพูดอยู่แล้ว และการลบออกนั้นเป็นไปไม่ได้ (อย่างน้อยฉันก็รู้) - person Mikael Persson; 03.05.2011
comment
@มิคาเอล: คุณพูดถูก ฉันเพิ่งมาถึงข้อสรุปนี้ด้วยตัวเอง - person J T; 04.05.2011
comment
ฉันขอแนะนำให้คุณแก้ไขปัญหาประเภทนี้ด้วยระบบบิลด์แทน (เช่น cmake เป็นต้น) หรือด้วยสคริปต์ที่ทำเองที่บ้าน นั่นคือวิธีที่ Qt สร้างส่วนหัวสำหรับไฟล์ .ui เป็นต้น - person Mikael Persson; 04.05.2011
comment
ใช่ ฉันหันไปใช้ GCC และ Make: gcc -c -DEVALUTOR_ARGUMENT=$‹ $‹ - person J T; 04.05.2011
comment
ว้าว ดีและเรียบง่าย! ดีมาก. - person Mikael Persson; 04.05.2011

สิ่งนี้เกิดขึ้นจริงในแผนผังต้นทางของ Linux; ดู บรรทัด 100 ของคอมไพเลอร์- gcc.h.

#define __gcc_header(x) #x
#define _gcc_header(x) __gcc_header(linux/compiler-gcc##x.h)
#define gcc_header(x) _gcc_header(x)
#include gcc_header(__GNUC__)

ฉันกำลังพยายามหาวิธีสร้างสตริงตัวแปรสำหรับคำสั่ง #include โดยใช้ GCC

โทเค็นนี้จะวางค่า __GNUC__ ลงในสตริง "linux/compiler-gcc" __GNUC__ ".h" จากนั้นจึงสตริงผลลัพธ์ นี่อาจเป็นส่วนขยายตัวประมวลผลล่วงหน้า gcc

นี่คือตัวอย่าง

t1.h

#define FOO 10

t2.h

#define FOO 20

a.c

#ifndef VERSION
#define VERSION 1
#endif
#define __gcc_header(x) #x
#define _gcc_header(x) __gcc_header(t##x.h)
#define gcc_header(x) _gcc_header(x)
#include gcc_header(VERSION)
#include <stdio.h>

int main(void)
{
        printf("FOO is %d\n", FOO);
        return 0;
}

นี่คือสองคอมไพล์

g++ -o a a.cc
g++ -DVERSION=2 -o a a.cc

ผลลัพธ์ของการคอมไพล์อย่างใดอย่างหนึ่งให้ผลลัพธ์ที่คาดหวัง

เช่นเดียวกับซอร์ส Linux คุณสามารถคีย์ค่าที่กำหนดไว้ล่วงหน้าของ gcc ได้ echo | g++ -dM -E - จะให้รายการ

ในกรณีของคุณ คุณสามารถใช้ makefile เพื่อส่งการกำหนดไปยังการคอมไพล์เพื่อให้รวมส่วนหัวที่สร้างขึ้นแบบไดนามิกโดยไม่ต้องเปลี่ยนแหล่งที่มา แต่ทางเลือกง่ายๆ ก็คือเรียกใช้ sed ฯลฯ บนไฟล์ต้นฉบับเทมเพลตแล้วแทนที่ด้วยชื่อรวมที่รู้จัก

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

person artless noise    schedule 12.12.2013
comment
คุณไม่สามารถใช้ __FILE__ ได้แน่นอนตามที่คนอื่นชี้ให้เห็น ใน C ++ และ C ล่าสุดนั้น มันเป็นตัวชี้และไม่ใช่ตัวอักษรสตริง (ตาม arelius) - person artless noise; 12.12.2013
comment
Linux รวมไฟล์และใช้เงื่อนไขตัวประมวลผลล่วงหน้าเพื่อตรวจสอบทันที นี่คือ ลิงก์ไปยังเวอร์ชันเก่า ความเป็นไปได้อีกอย่างหนึ่งคือ has_include extensions ใน GCC ใหม่ทั้งสอง และเสียงดังกราว - person artless noise; 17.06.2016

ฉันค่อนข้างแน่ใจว่าคุณไม่สามารถทำสิ่งที่คุณต้องการได้ __FILE__ ส่งคืนสตริงและ ## ทำงานบนโทเค็น และไม่มีมาโครตัวประมวลผลล่วงหน้า concat สตริง CPP โดยปกติสิ่งนี้จะเกิดขึ้นได้เนื่องจากการมีสองสายติดต่อกันเช่น

"Hello" " World"

ตัวแยกวิเคราะห์ C++ จะถือเป็นสตริงเดี่ยว อย่างไรก็ตาม #include เป็นส่วนหนึ่งของตัวประมวลผลล่วงหน้า จึงไม่สามารถใช้ประโยชน์จากข้อเท็จจริงนั้นได้

คำตอบเก่า:

ทำไมคุณทำเช่นนี้

{ #str, str ## .iden }

ฉันแน่ใจว่านั่นไม่ใช่ไวยากรณ์ของตัวประมวลผลล่วงหน้า คุณหวังว่าจะบรรลุผลอะไรจากสิ่งนั้น คุณลองแล้วหรือยัง:

str ## .iden

เครื่องหมาย '{' อาจอธิบายข้อผิดพลาดที่คุณได้รับ

person Arelius    schedule 03.05.2011
comment
น่าเสียดายที่ฉันลองใช้วิธีหลังก่อนหน้านี้และได้รับข้อผิดพลาดเดียวกัน แนวทางที่ฉันใช้มาจากเอกสาร GCC: tigcc.ticalc.org/doc/cpp html#SEC18 - person J T; 03.05.2011

ข้ามเรื่องไวยากรณ์การรวมทั้งหมดไปสักระยะหนึ่ง ฉันไม่เข้าใจว่าโค้ดของคุณพยายามทำอะไร คุณพูด:

# define PASTER(str)  { #str, str ## .iden }

คุณให้ main.c และคาดหวัง "main.c.iden" แต่นั่นกลับเป็น {"main.c", main.c.iden }

คุณกำลังมองหาสิ่งนี้แทนใช่ไหม?

#define PASTER2(str) #str
#define PASTER(str) PASTER2(str ## .iden)
person Blindy    schedule 03.05.2011
comment
คุณถูกต้องและฉันได้ทำการเปลี่ยนแปลงแล้ว แต่น่าเสียดายที่ทำให้เกิดข้อผิดพลาดเดียวกัน - person J T; 03.05.2011

คุณไม่สามารถใช้ตัวประมวลผลล่วงหน้าเช่นนี้ได้ คุณต้องระบุชื่อไฟล์ให้กับคำสั่ง #include ซึ่งไม่สามารถเป็นมาโครอื่นได้

person ognian    schedule 03.05.2011
comment
สิ่งนี้ฉันรู้ว่าไม่ถูกต้อง (ค้นหาด้วยการคำนวณรวม): tigcc.ticalc.org/doc/cpp.html - person J T; 03.05.2011
comment
@JT นั่นเป็นคุณสมบัติของตัวประมวลผลล่วงหน้า GCC - ไม่ได้เป็นส่วนหนึ่งของมาตรฐาน C หรือ C ++ สำหรับการประมวลผลล่วงหน้า - person ; 03.05.2011
comment
@JT จริงๆ แล้วเขาถูกต้องมาก การคำนวณรวมเป็นส่วนขยาย GCC และคุณไม่ได้แท็กคำถามของคุณเป็น GCC เท่านั้น - person Blindy; 03.05.2011
comment

มีสไปรท์เอ็นจิ้นที่ใช้ Silverlight อยู่...อย่าวางใจว่าพวกมันจะทำให้ลูกค้าของคุณว้าว ฉันเห็นด้วยกับ ctatke: อัปเกรดการ์ดวิดีโอของคุณหรือสลับเครื่อง dev และดำเนินการให้ถูกต้อง

Googling "Silverlight sprite engine" เกิดขึ้นกับสิ่งนี้... อาจจะมากกว่านั้นหากคุณต้องการขุด:

http://slspriteengine.codeplex.com/

ขอให้โชคดี!

-จอห์น

- person J T; 03.05.2011
comment
หากคุณต้องการใช้ส่วนขยาย GNU คุณควรลบวงเล็บขอบเขตออกจากมาโครของคุณ อย่างไรก็ตาม พยายามที่จะพกพาสะดวก มันก็จะตอบแทน - person ognian; 03.05.2011
comment
รวมการคำนวณจริง (หรือบางรูปแบบ) ได้รับอนุญาตจากมาตรฐาน C --- มาตรฐาน C99 ดู 6.10.2/4 ... "# include pp-tokens newline" โดยที่ pp-token ต้องขยายเป็น <header> หรือ "header-file" - person pmg; 03.05.2011