Раскрытие макроса в строку
Вот здесь описывается как организовать автоинкремент версии файла.
В частности там есть такие строки
#define VERSION_MAJOR 1
#define VERSION_MINOR 0
#define VERSION_PATCH 0
#define VERSION_BUILD 0
#define stringify(a) stringify_(a)
#define stringify_(a) #a
и потом использование
VALUE "FileVersion", stringify(VERSION_MAJOR) "." stringify(VERSION_MINOR) "." stringify(VERSION_PATCH) "." stringify(VERSION_BUILD)
Все работает, но я не пойму как. Как работает здесь макрос stringify?
Причем если объявить его так
#define stringify(a) #a
То тогда в FileVersion записывается строка VERSION_MAJOR.VERSION_MINOR.VERSION_PATCH.VERSION_BUILD
Что это за конструкция такая #a и почему ее нужно вкладывать в другой макрос?
Ответы (2 шт):
#a - это конструкция препроцессора (это важно, так как он деюре работает до компилятора), которая значит ровно одно - замени #a на "a".
Когда Вы пишите
#define stringify(a) #a
VERSION_MAJOR(VERSION)
то препроцессор именно это и делает - он просто подставляет и получается "VERSION".
Когда же используется первый, правильный способ, то в первую итерацию раскрывается вот так
stringify(VERSION_MAJOR) "."
превращается в
stringify_(1) "."
и препроцессор обнаруживает, что там ещё есть макросы и делает вторую иттерацию
"1" "."
а потом уже такие строки склеиваются в
"1."
Stringification поясняет что #a превращает свой аргумент в строку. Но есть особенность:
Unlike normal parameter replacement, the argument is not macro-expanded first. This is called stringification.
Аргумент не вычисляется перед превращением в строку. Это приводит к тому что stringify_(VALUE) раскрывается в "VALUE".
А если раскрывать stringify(VALUE), то перед передачей во вложенный макрос параметр раскроется и получится stringify_(1), который затем раскроется в "1".
Двойная вложенность заставляет препроцессор вычислить значение до стрингификации.
Попробуйте сами:
#define VALUE 1234
#define stringify(a) stringify_(a)
#define stringify_(a) #a
#include <stdio.h>
int main() {
puts(stringify_(VALUE));
puts(stringify(VALUE));
}
$ gcc stringify.c && ./a.out VALUE 1234
Вам, наверно, интересно почему препроцессор везде вычисляет параметры а при стрингификации нет? Чтобы работали такие штуки:
#include <stdio.h>
#define DUMP(expr) printf("%s = %d\n", #expr, (expr))
#define VALUE 42
int main() {
int a = 2;
int b = 3;
DUMP(a + b);
DUMP(VALUE);
DUMP(a + b + VALUE);
}
$ gcc stringify.c && ./a.out a + b = 5 VALUE = 42 a + b + VALUE = 47