C Makro - Dinamis #include

Saya mencoba mencari cara membuat string variabel untuk pernyataan #include menggunakan GCC.

Idenya adalah bahwa untuk setiap modul sumber yang saya tulis, saya ingin menyertakan sebagai header, sumber C yang dihasilkan secara dinamis, yang dibuat sebelumnya dalam proses pembangunan.

Menghasilkan file ini tidak menjadi masalah. Sayangnya, termasuk itu.

Apa yang saya miliki sejauh ini adalah (identitas.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

Idealnya, ini akan digunakan seperti ini (main.c):

//main.c

# include "identities.h"

int main() {return 0;}

Yang akan diperluas dalam satu lintasan oleh praprosesor sebelum kompilasi untuk menghasilkan:

//main.c (preprocessed)

# include "main.c.iden"

int main() {return 0;}

Dua tingkat tipuan yang saya gunakan (PASTER dan EVALUATOR) adalah hasil dari ini kiriman.

Sayangnya, ini tidak berhasil dan saya mengalami kesalahan:

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

Saya pikir masalahnya adalah pernyataan include tidak ada tanda kutipnya.. Ada ide?


person J T    schedule 03.05.2011    source sumber
comment
Jika Anda memiliki sumber C yang dibuat secara dinamis, dapatkah Anda secara dinamis membuat file header baru dari semua file header yang ingin Anda sertakan? Meskipun saya masih penasaran untuk melihat apakah mungkin melakukan apa yang ingin Anda lakukan.   -  person leetNightshade    schedule 03.05.2011
comment
Jawaban singkatnya: Anda tidak bisa melakukan ini, titik.   -  person Alexandre C.    schedule 03.05.2011
comment
@leet: Tidak, masalahnya memerlukan pendekatan minimalis mutlak untuk memodifikasi sistem build saat ini. Telah disepakati bahwa kami akan mencoba melakukan ini, dengan mengedit setiap file untuk menyertakan satu header generik identities.h - dan hanya satu file itu.   -  person J T    schedule 03.05.2011
comment
@AlexandreC. Aneh, aku bisa melakukan ini. Saya tidak boleh ada di alam semesta Anda ;-). Saya pikir maksud Anda Anda tidak dapat melakukan ini dengan standar C/C++.   -  person artless noise    schedule 13.12.2013


Jawaban (5)


Bagaimana dengan BOOST_PP_STRINGIZE dari pustaka Boost Preprocessor . Ini khusus dibuat untuk menambahkan tanda kutip di sekitar nama.

person Mikael Persson    schedule 03.05.2011
comment
Sayangnya, yang dilakukan hanyalah menambahkan satu pon sebelum teks: # definisikan BOOST_PP_STRINGIZE_I(teks) #teks - person J T; 03.05.2011
comment
BOOST_PP_STRINGIZE tidak hanya menambah satu pon#. Dokumen tersebut secara khusus mengatakan bahwa dibandingkan hanya menggunakan #, makro ini sebenarnya mengizinkan argumennya diperluas (dan # tidak). Setelah beberapa pengujian, tampaknya masalah utama Anda adalah FILE meluas ke nama file yang sudah ada di antara tanda kutip, dan menghapusnya tidak mungkin dilakukan (setidaknya, yang saya tahu). - person Mikael Persson; 03.05.2011
comment
@Mikael: Anda benar, saya sendiri yang sampai pada kesimpulan ini. - person J T; 04.05.2011
comment
Saya sarankan Anda menyelesaikan masalah seperti ini dengan sistem build (seperti cmake misalnya) atau dengan skrip buatan sendiri. Begitulah cara Qt menghasilkan header untuk file .ui misalnya. - person Mikael Persson; 04.05.2011
comment
Ya, saya terpaksa menggunakan GCC dan Make: gcc -c -DEVALUTOR_ARGUMENT=$‹ $‹ - person J T; 04.05.2011
comment
Wow, itu bagus dan sederhana! Bagus sekali. - person Mikael Persson; 04.05.2011

Ini sebenarnya dilakukan di pohon sumber Linux; Lihat baris 100 kompiler- 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__)

Saya mencoba mencari cara membuat string variabel untuk pernyataan #include menggunakan GCC.

Token ini menempelkan nilai __GNUC__ ke sebuah string; "linux/compiler-gcc" __GNUC__ ".h" dan kemudian merangkai hasilnya. Ini mungkin merupakan ekstensi pra-prosesor gcc.

Ini contohnya,

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;
}

Berikut adalah dua kompilasi,

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

Output dari kompilasi mana pun memberikan hasil yang diharapkan.

Seperti halnya sumber Linux, Anda dapat mematikan nilai gcc yang telah ditentukan sebelumnya. echo | g++ -dM -E - akan memberikan daftarnya.

Untuk kasus Anda, Anda dapat menggunakan makefile untuk meneruskan definisi ke kompilasi untuk memungkinkan penyertaan dinamis dari header yang dihasilkan tanpa mengubah sumbernya. Namun alternatif sederhananya adalah dengan menjalankan sed, dll pada file sumber templat dan menggantinya dengan nama penyertaan yang dikenal.

Teknik mana pun bagus untuk menghasilkan perlengkapan pengujian, dll. Namun, untuk penemuan fitur kompiler, ini adalah metode yang lebih baik. Bagi programmer yang menggunakan IDE, ini mungkin satu-satunya pilihan mereka.

person artless noise    schedule 12.12.2013
comment
Anda tidak dapat menggunakan __FILE__ tentu saja seperti yang ditunjukkan orang lain. Dalam C++ dan C yang lebih baru, ini adalah pointer dan bukan string literal (sesuai arelius). - person artless noise; 12.12.2013
comment
Linux menggabungkan file dan cukup gunakan kondisi pra-prosesor untuk memeriksanya sekarang. Ini adalah tautan ke versi lama. Kemungkinan lainnya adalah has_include extensions di kedua GCC baru dan dentang. - person artless noise; 17.06.2016

Saya cukup yakin Anda tidak dapat melakukan apa yang Anda inginkan, __FILE__ mengembalikan string dan ## berfungsi pada token dan tidak ada makro praprosesor concat string CPP. Biasanya hal ini terjadi karena fakta bahwa dua string berturut-turut mis.

"Hello" " World"

akan diperlakukan sebagai string tunggal oleh parser C++, namun #include adalah bagian dari praprosesor, sehingga tidak dapat memanfaatkan fakta tersebut.

Jawaban lama:

Mengapa kau melakukan ini

{ #str, str ## .iden }

Saya yakin itu bukan sintaks praprosesor, apa yang ingin Anda capai melalui itu? Sudahkah Anda mencoba:

str ## .iden

Tanda '{' dapat menjelaskan kesalahan yang Anda dapatkan.

person Arelius    schedule 03.05.2011
comment
Sayangnya, saya mencoba pendekatan terakhir sebelumnya dan mendapatkan kesalahan yang sama. Pendekatan yang saya gunakan berasal dari dokumentasi GCC: tigcc.ticalc.org/doc/cpp. html#SEC18 - person J T; 03.05.2011

Melewatkan seluruh sintaks penyertaan untuk sementara waktu, saya tidak mengerti apa yang coba dilakukan kode Anda. Kamu bilang:

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

Anda memberikannya main.c dan mengharapkan "main.c.iden", tetapi itu menghasilkan {"main.c", main.c.iden }.

Apakah Anda malah mencari ini?

#define PASTER2(str) #str
#define PASTER(str) PASTER2(str ## .iden)
person Blindy    schedule 03.05.2011
comment
Anda benar dan saya telah mengubahnya, meskipun sayangnya menghasilkan kesalahan yang sama.. - person J T; 03.05.2011

Anda tidak dapat menggunakan praprosesor seperti ini. Anda harus memberikan nama file ke direktif #include, tidak boleh makro lainnya.

person ognian    schedule 03.05.2011
comment
Ini yang saya tahu salah (penelusuran yang Dihitung Termasuk): tigcc.ticalc.org/doc/cpp.html - person J T; 03.05.2011
comment
@JT Itu adalah fitur praprosesor GCC - ini bukan bagian dari standar C atau C++ untuk prapemrosesan. - person ; 03.05.2011
comment
@JT, Sebenarnya dia benar, penyertaan yang dihitung adalah ekstensi GCC dan Anda tidak menandai pertanyaan Anda sebagai khusus GCC. - person Blindy; 03.05.2011
comment

Ada mesin sprite berbasis Silverlight...jangan mengandalkannya untuk membuat pelanggan Anda kagum. Saya setuju dengan ctatke: tingkatkan kartu video Anda atau ganti mesin pengembang dan selesaikan dengan benar.

Googling "Silverlight sprite engine" menghasilkan ini...mungkin lebih jika Anda ingin menggali:

http://slspriteengine.codeplex.com/

Semoga beruntung!

-John

- person J T; 03.05.2011
comment
Jika Anda ingin mengandalkan ekstensi GNU, Anda harus menghapus tanda kurung cakupan dari makro Anda. Namun cobalah untuk tetap portabel, ada manfaatnya - person ognian; 03.05.2011
comment
Sebenarnya Penyertaan Terhitung (atau beberapa bentuknya) diizinkan oleh Standar C --- Standar C99. Lihat 6.10.2/4 ... "# include pp-tokens newline" di mana pp-token harus diperluas ke salah satu dari <header> atau "header-file" - person pmg; 03.05.2011