Gabungkan int ke string menggunakan C Preprocessor

90

Saya mencoba untuk mencari tahu bagaimana saya bisa menggabungkan #define'd int ke #define' d string menggunakan C Preprocessor. Kompiler saya adalah GCC 4.1 di CentOS 5. Solusinya juga harus berfungsi untuk MinGW.

Saya ingin menambahkan nomor versi ke string, tetapi satu-satunya cara agar saya dapat berfungsi adalah membuat salinan nomor versi yang didefinisikan sebagai string.

Hal terdekat yang bisa saya temukan adalah metode mengutip argumen makro, tetapi tidak berhasil untuk #defines

Ini tidak berhasil.

#define MAJOR_VER 2
#define MINOR_VER 6
#define MY_FILE "/home/user/.myapp" #MAJOR_VER #MINOR_VER

Itu tidak bekerja tanpa #s juga karena nilainya adalah angka dan akan berkembang menjadi "/home/user/.myapp" 2 6, yang bukan C yang valid .

Ini berfungsi, tetapi saya tidak suka memiliki salinan dari versi yang ditentukan karena saya membutuhkannya sebagai angka juga.

#define MAJOR_VER 2
#define MINOR_VER 6
#define MAJOR_VER_STR "2"
#define MINOR_VER_STR "6"
#define MY_FILE "/home/user/.myapp" MAJOR_VER_STRING MINOR_VER_STRING
jonescb.dll
sumber
3
Kemungkinan duplikat dari Ubah token preprocessor menjadi string
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Jawaban:

172

Pertanyaan klasik C preprocessor ....

#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)

#define MAJOR_VER 2
#define MINOR_VER 6
#define MY_FILE "/home/user/.myapp" STR(MAJOR_VER) STR(MINOR_VER)

Tingkat tipuan ekstra akan memungkinkan preprocessor untuk memperluas makro sebelum diubah menjadi string.

Lindydancer
sumber
3
STR () dalam hal ini akan memberikan string Narrow. Apakah ada variasi untuk mengubahnya menjadi string lebar?
gkns
5
Saya tidak bisa mengatakan berapa kali saya mencarinya di Google dan menyalin dari jawaban yang tepat ini, tetapi hasilnya akan menjadi dua digit
MightyPork
1
"STR_HELPER" pertama diperlukan karena '#' hanya berfungsi dengan argumen makro. Aku butuh waktu untuk memikirkannya ..
clarkttfu
1
@clarkttfu, semacam - ya, #hanya berfungsi dengan argumen makro. Namun, STR_HELPERmakro diperlukan untuk menghindari mengubah makro MAJOR_VERmenjadi string "MAJOR_VAR", di mana kita ingin mendapatkan hasilnya "2".
Lindydancer
13

Cara kerjanya adalah dengan menulis MY_FILE sebagai makro parametrik:

#define MY_FILE(x,y) "/home..." #x #y

EDIT: Seperti dicatat oleh "Lindydancer", solusi ini tidak memperluas makro dalam argumen. Solusi yang lebih umum adalah:

#define MY_FILE_(x,y) "/home..." #x #y
#define MY_FILE(x,y) MY_FILE_(x,y)
Giuseppe Guerrini
sumber
1
Sejujurnya, ini adalah jawaban terbaik, dan jauh lebih sederhana daripada saran lainnya. Saya terkejut itu tidak mendapatkan peringkat yang lebih baik!
osirisgothra
5
Ini adalah solusi bersih yang sayangnya tidak berhasil. Jika argumen yang diteruskan ke MY_FILEadalah makro, katakan Adan B, makro ini akan diperluas menjadi "/home..." "A" "B".
Lindydancer
2

Anda dapat melakukannya dengan BOOST_PP_STRINGIZE :

#define MAJOR_VER 2
#define MINOR_VER 6
#define MY_FILE "/home/user/.myapp" BOOST_PP_STRINGIZE(MAJOR_VER) BOOST_PP_STRINGIZE(MINOR_VER)
Maxim Egorushkin
sumber
28
Bikin aku menyeringai bagaimana orang melempar Boost dalam segala hal.
Frerich Raabe
4
@Frerich: Mengambil argumen Anda secara ekstrem, orang harus menulis kompiler mereka sendiri terlebih dahulu dalam kode mesin mentah, daripada membuang g ++ pada semuanya ... Tidak ada gunanya menemukan kembali roda. Pemrogram yang baik menulis kode, yang hebat digunakan kembali.
Maxim Egorushkin
@jonescb: cukup buka header boost dan lihat sendiri.
Maxim Egorushkin
10
Ya, saya mencobanya. Itu berhasil, tetapi menggunakan tajuk Boost dalam program C tampaknya agak aneh bagi saya.
jonescb
1
Oh, saya buruk, tidak melihat Ctag.
Maxim Egorushkin