#gcc #c-preprocessor
#gcc #c-препроцессор
Вопрос:
Почему некоторые строки заменяются, а другие не заменяются на #define?
$ cat test.c
#define X_ REPLACED
int main() {
X_x();
X_();
return 0;
}
$ gcc -E test.c
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "test.c"
int main() {
X_x();
REPLACED();
return 0;
}
Приведенное выше X_();
заменено, но X_x();
это не так. Каковы правила? Я нигде не могу найти никакой информации об этом, несмотря на долгое расследование.
Причина, по которой я смотрю на это: я хочу создать ссылку на библиотеку FFT (FFTW), имена процедур которой начинаются с fftwf_, fftw_, fftwl_ или fftwq_, в зависимости от того, используется ли одинарная, двойная, длинная двойная или квадратичная точность.
(версия gcc: 4.4.3)
Комментарии:
1. Я могу начать понимать причину вашего желания этого, но вам следует уточнить подробнее. Вы пытаетесь написать свой код так, чтобы он работал независимо от того, какой из них используется, чтобы несколько
#define
s или-D
флагов могли изменять набор, используемый вашим кодом?
Ответ №1:
Поскольку препроцессор работает по каждому токену и X_x
считается как один токен, следовательно, он игнорируется #define
. Если вам нужно X_x
стать REPLACEDx()
, используйте sed или любое другое регулярное выражение для предварительной обработки кода.
Поскольку макросы являются немыми, анализ аргументов невозможен, поэтому вы не можете выполнить `#define fft_func(mytype Если вы хотите выполнить этот эффект без регулярных выражений, используйте
#define CONCAT2(x, y) x##y
#define CONCAT(x, y) CONCAT2(x, y)
#define FFTW_FUNC(fft_type, fft_func) CONCAT(CONCAT(CONCAT(fftw, fft_type), _), fft_func)
int main() {
// ...
FFTW_FUNC(type, func)(args);
// ...
}
Для типов БПФ:
#define FFTWT_FLOAT f
#define FFTWT_DOUBLE
#define FFTWT_LONG_DOUBLE l
#define FFTWT_QUAD_PRECISION q
Комментарии:
1. Вот пример того, насколько плохо это было бы: #define max(a,b) … (теперь поищите, где у вас есть «max» где угодно ).
2. Вы, конечно, имеете в виду
#define CONCAT(x, y) CONCAT2(x, y)
3. @ChrisLutz исправлено; я знал, что забыл кое-что добавить
4. @crashmstr У кувалды есть свое применение. Полировка тонкого фарфора не входит в их число. Программист должен быть рассудительным.
5. Я бы использовал
#ifndef FFTW_TYPE
/#define FFTWT FFTWT_DOUBLE
/#endif
/#define FFTW(funcname) FFTW_FUNC(FFTWT, funcname)
, чтобы пользователь мог передать-DFFTWT=FFTWT_LONG_DOUBLE
в командной строке и изменить то, что использует скомпилированный файл. Небольшое дополнительное оборудование могло бы настроить соответствующийtypedef
, и если бы в какой-то момент для части кода абсолютно требовался определенный тип, он все равно был бы доступен.
Ответ №2:
Спасибо, это именно то, чего я хотел. Я немного отредактировал ваше решение следующим образом:
#ifdef single
#define myType fftwf_
#else
#ifdef double
#define myType fftw_
#endif
#endif
#define CONCAT(x, y) x##y
#define FFTW_FUNC(fft_type, fft_func) CONCAT(fft_type, fft_func)
int main() {
//
FFTW_FUNC(myType, func)(args);
//
}
Вышесказанное дает:
$ gcc -E -Ddouble test.c; gcc -E -Dsingle test.c
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "test.c"
# 12 "test.c"
int main() {
fftw_func(args);
}
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "test.c"
# 12 "test.c"
int main() {
fftwf_func(args);
}