Предварительные наблюдения
Обратите внимание, что в C (в отличие от C ++) вы не можете инициализировать массив static const char str[]
с результатом вызова функции.Если strrchr()
обнаружил обратную косую черту, вы, вероятно, захотите напечатать имя из одной после обратной косой черты.И строковая спецификация не собирается приводить к строковому результату вызова strrchr()
.
. Также обратите внимание, что в общем случае не следует создавать имена функций или переменных, начинающиеся с подчеркивания. C11 §7.1.3 Зарезервированные идентификаторы говорит (частично):
- Все идентификаторы, которые начинаются со знака подчеркивания, либо с заглавной буквы, либо другого знака подчеркивания,всегда зарезервировано для любого использования.
- Все идентификаторы, начинающиеся с подчеркивания, всегда зарезервированы для использования в качестве идентификаторов с областью действия файла как в обычном пространстве, так и в пространстве имен тега.
См. Также Что означает двойное подчеркивание (__const
) в C?
Поскольку первый аргумент вашего макроса TRACE уже является строкой, естьне очень полезно применять строковую классификацию - если вы не хотите, чтобы двойные кавычки появлялись при печати имени.
Простая адаптация
Чтобы получить более или менее желаемый результат, вам потребуетсясогласитесь, что во время выполнения будут накладываться strrchr()
каждый раз, когда вы будете проходить трассировку (или более сложную схему инициализации), в соответствии с:
#define TRACE(s, ...) \
do { \
const char *basename = strrchr(s, '\\'); \
if (basename == 0) \
basename = s; \
else \
basename++; \
printf(basename, ## __VA_ARGS__); \
} while (0)
идиома do { … } while (0)
iстандарт s;это позволяет вам написать:
if (something)
TRACE("hocuspocus.c: test passed\n");
else
TRACE("abracadabra.c: test failed\n");
Если вы используете в вопросе только фигурные скобки, точка с запятой после первой TRACE приводит к синтаксической ошибке else
.См. Также макрос C #define
для отладочной печати и Зачем использовать явно макросы do { … } while (0)
и if … else
в макросах? и do { … } while (0)
- что это хорошодля?
Трюк ## __VA_ARGS__
подойдет, если вы знаете, что это расширение GCC (и Clang, потому что оно совместимо с GCC), а не часть стандартного C.
Также не совсем понятно, как вы планируете использовать переменные аргументы.Выглядит так, как будто вы могли бы сделать:
TRACE("some\\kibbitzer.c: value %d is out of the range [%d..%d]\n",
value, MIN_RANGE, MAX_RANGE);
, где имя файла встроено в строку формата.Возможно, вы имеете в виду:
TRACE(__FILE__ ": value %d is out of the range [%d..%d]\n",
value, MIN_RANGE, MAX_RANGE);
Это может сработать;__FILE__
является строковым литералом, в отличие от __func__
, который является предопределенным идентификатором (static const char __func__[] = "…function name…";
).
Наконец (пока), подумайте, должен ли вывод трассировки идти в стандартный вывод или в стандартную ошибку.Легко утверждать, что это должно идти к стандартной ошибке;это (вероятно) не является частью обычной работы программы.
Я рекомендую взглянуть на вопрос и ответ «Макрос отладки» - но я предвзят, поскольку написал ответ с наивысшими оценками.
Сокращение накладных расходов времени выполнения
Вы можете уменьшить накладные расходы времени выполнения до одного вызова до strrchr()
для имени файла, если вы не будете связываться с автоматическими переменными и т. Д. Вы будете в порядке, есливы используете строковые литералы.
#define TRACE(s, ...) \
do { \
static const char *basename = 0;
if (basename == 0) \
{
if ((basename = strrchr(s, '\\')) == 0) \
basename = s; \
else \
basename++; \
} \
printf(basename, ## __VA_ARGS__); \
} while (0)
Это инициализирует basename
в ноль;при первом проходе по коду basename
устанавливается в правильную позицию в строке;после этого больше нет вызова strrchr()
.
Предупреждение: указанный код не был скомпилирован.