Как написать условие в макросе?

378
29 июня 2021, 17:30

Есть у меня вот такой рабочий файл

#ifndef ANDROID_LOGGING_H
#define ANDROID_LOGGING_H
#include <stdio.h>
#include <android/log.h>
#include <vector>
#define APP_NAME "MyApp"
#define IS_DEBUGG true
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, APP_NAME, __VA_ARGS__))
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, APP_NAME, __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, APP_NAME, __VA_ARGS__))
#define LOGE(...) ((void) __android_log_print(ANDROID_LOG_ERROR, APP_NAME, __VA_ARGS__))
#define CHECK(condition)                                                   \
  if (!(condition)) {                                                      \
    LOGE("*** CHECK FAILED at %s:%d: %s", __FILE__, __LINE__, #condition); \
    abort();                                                               \
  }
#endif //ANDROID_LOGGING_H

Я вижу, что в макросе CHECK используется условие

#define CHECK(condition)                                                   \
  if (!(condition)) {                                                      \
    LOGE("*** CHECK FAILED at %s:%d: %s", __FILE__, __LINE__, #condition); \
    abort();                                                               \
  }

Значит использовать условия в макросах можно, от сюда я придумал дописать условие в лог

Вот так

#define LOGE(...) ((void) if(IS_DEBUGG) __android_log_print(ANDROID_LOG_ERROR, APP_NAME, __VA_ARGS__))

Но теперь везде где я использую LOGE("error"); мне подсвечивает и говорит, что не хватает какого то знака syntax error (, ), ;

Как написать условие в макросе?

EDIT

#define IS_DEBUGG true
#if(IS_DEBUGG)
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, APP_NAME, __VA_ARGS__))
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, APP_NAME, __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, APP_NAME, __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, APP_NAME, __VA_ARGS__))
#endif
Answer 1

Это условие не в макросе, а вставляется в код. Условные директивы для препроцессора пишутся так:

#if(IS_DEBUGG)
#define LOGE(...) ((void) __android_log_print(ANDROID_LOG_ERROR, APP_NAME, __VA_ARGS__))
#else
#define LOGE(...)
#endif
Answer 2

В макросах почти нет никаких "можно" или "нельзя". Макросы - это текстовые подстановки. Писать в них можно почти что угодно. Фактически "использоваться", правда, это все будет не в макросе, а в месте его подстановки.

Вы все сделали почти правильно, кроме какого-то странного (void), который вы впихнули в ваш макрос ни к селу, ни к городу. Неудивительно, что в месте подстановки такого макроса возникает ошибка из-за этого (void). Правильно

#define LOGE(...)\
  if (IS_DEBUGG)\
    __android_log_print(ANDROID_LOG_ERROR, APP_NAME, __VA_ARGS__)

Можно добавить (void) непосредственно перед вызовом функции, как это сделано в остальных вызовах, если этого (void) требует принятые у вас правила написания кода

#define LOGE(...)\
  if (IS_DEBUGG)\
    ((void) __android_log_print(ANDROID_LOG_ERROR, APP_NAME, __VA_ARGS__))

Однако такой вариант макроса страдает от одной неприятной проблемы, которая присуща и приведенному вами макросу CHECK тоже. Если кто-то когда-напишет вполне естественно выглядящий код вида

if (условие1)
  CHECK(условие2);
else
  что-то;

то такой код приведет к ошибке "оторванного" else.

А если кто-то использует

if (условие)
  LOGE(параметры);
else
  что-то;

то такой код будет проинтерпретирован компилятором как

if (условие)
  if (IS_DEBUGG) 
     __android_log_print(ANDROID_LOG_ERROR, APP_NAME, параметры);
  else
    что-то;

То есть else будет неожиданно отнесен совсем не к тому if, к которому собирался отнести его автор кода.

По этим причинам при написании подобных макросов следует придерживаться определенных правил. Как минимум, в if верхнего уровня старайтесь всегда указывать обе ветки if и ваш код писать именно в ветке else

#define CHECK(condition)                                                   \
  if (condition); else {                                                   \
    LOGE("*** CHECK FAILED at %s:%d: %s", __FILE__, __LINE__, #condition); \
    abort();                                                               \
  }                                                                        
#define LOGE(...)                                                          \
  if (!IS_DEBUGG); else                                                    \
    ((void) __android_log_print(ANDROID_LOG_ERROR, APP_NAME, __VA_ARGS__))

Но лучше такие составные макросы всегда заключать в операторные скобки do ... while (0)

#define CHECK(condition)                                                     \
  do                                                                         \
    if (!(condition)) {                                                      \
      LOGE("*** CHECK FAILED at %s:%d: %s", __FILE__, __LINE__, #condition); \
      abort();                                                               \
    }                                                                        \
  while (0)
#define LOGE(...)                                                            \
  do                                                                         \
    if (IS_DEBUGG)                                                           \
      (void) __android_log_print(ANDROID_LOG_ERROR, APP_NAME, __VA_ARGS__);  \
  while (0)

В вашем случае, когда условие является константой препроцессора (IS_DEBUGG) лучше, наверное, применить принципиально иной подход из ответа @VTT. Однако это ни в коем случае не обязательно. Ваш оригинальный подход вполне жизнеспособен и обладает своим набором преимуществ.

READ ALSO
Поиск слов в .txt файле

Поиск слов в .txt файле

Суть моей задачи в том , что надо искать определенные лексемы в файлахЕсли лексема есть, то выводить значение после него

88
html css flex-box

html css flex-box

Подскажите как расположить изображения ?

279
Application.Exit() не закрывает приложение

Application.Exit() не закрывает приложение

Есть поток, который выполняется бесконечно:

102