Łączenie int z ciągiem znaków przy użyciu preprocesora języka C

90

Próbuję dowiedzieć się, jak mogę połączyć #define„d int z #defineciągiem” za pomocą preprocesora C. Mój kompilator to GCC 4.1 na CentOS 5. Rozwiązanie powinno również działać dla MinGW.

Chciałbym dołączyć numer wersji do łańcucha, ale jedynym sposobem, w jaki mogę go uruchomić, jest zrobienie kopii numeru wersji zdefiniowanego jako ciągi.

Najbliższą rzeczą, jaką udało mi się znaleźć, była metoda cytowania argumentów makr, ale nie działa ona w przypadku #defines

To nie działa.

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

To nie działa bez #s albo ponieważ wartości są liczbami i byłoby rozszerzyć do "/home/user/.myapp" 2 6, który nie jest ważny C .

To działa, ale nie lubię mieć kopii definicji wersji, ponieważ potrzebuję ich również jako liczb.

#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
źródło
3
Możliwy duplikat konwersji tokena preprocesora na łańcuch
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Odpowiedzi:

171

Pytanie dotyczące klasycznego preprocesora C ...

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

Dodatkowy poziom pośrednictwa pozwoli preprocesorowi rozwinąć makra, zanim zostaną przekształcone w łańcuchy.

Lindydancer
źródło
3
STR () w tym przypadku da Narrow string. Czy istnieje możliwość konwersji tego na szeroki ciąg?
gkns
5
Nie mogłem powiedzieć, ile razy google i skopiowałem z tej dokładnej odpowiedzi, ale będzie to dwucyfrowe
MightyPork,
1
Pierwszy „STR_HELPER” jest wymagany, ponieważ znak „#” działa tylko z argumentem makra. Zajęło mi trochę czasu, żeby to
rozgryźć
1
@clarkttfu, w pewnym sensie - tak, #działa tylko z argumentami makr. Jednak STR_HELPERmakro jest potrzebne, aby uniknąć zamiany makra MAJOR_VERna łańcuch "MAJOR_VAR", gdzie chcemy, aby wynik był "2".
Lindydancer
13

Działającym sposobem jest zapisanie MOJ_PLIK jako makra parametrycznego:

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

EDYCJA: Jak zauważył „Lindydancer”, to rozwiązanie nie rozszerza makr w argumentach. Bardziej ogólnym rozwiązaniem jest:

#define MY_FILE_(x,y) "/home..." #x #y
#define MY_FILE(x,y) MY_FILE_(x,y)
Giuseppe Guerrini
źródło
1
Moim zdaniem jest to najlepsza odpowiedź i jest znacznie prostsza niż inne sugestie. Jestem zaskoczony, że nie uzyskał lepszej oceny!
osirisgothra
5
To czyste rozwiązanie, które niestety nie działa. Jeśli argument przekazany do MY_FILEto makra, powiedzmy Ai B, to makro rozwinie się do "/home..." "A" "B".
Lindydancer
2

Możesz to zrobić za pomocą 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
źródło
28
Uśmiecham się, jak ludzie rzucają Boost na wszystko.
Frerich Raabe
4
@Frerich: Posuwając się do skrajności, ludzie powinni najpierw napisać własne kompilatory w surowym kodzie maszynowym, zamiast rzucać g ++ na wszystko ... Nie ma sensu wymyślać koła na nowo. Dobrzy programiści piszą kod, świetni ponownie wykorzystują.
Maxim Egorushkin
@jonescb: po prostu otwórz nagłówek Boost i przekonaj się sam.
Maxim Egorushkin
10
Tak, próbowałem. Zadziałało, ale używanie nagłówka Boost w programie C wydaje mi się trochę dziwne.
jonescb
1
Och, mój zły, nie zauważyłem Ctagu.
Maxim Egorushkin