Каковы некоторые приемы, которые я могу использовать с макросами? [закрытый]

Если это не все, что вам нужно, отредактируйте ваш вопрос, чтобы он был более понятным:

$ foo=$(awk '{print $4}' file)
$ bar=$(awk '{print $7}' file)
$ echo "$foo"
zxczxczxc
asdasdas
aqweqwea
$ echo "$bar"
zzzz
mmmm
zasd
26
задан 7 revs, 4 users 75%Sasha 4 February 2016 в 18:28
поделиться

20 ответов

В C распространено определить макросы, которые делают некоторый материал, получая дословный аргумент, и в то же время определяют функции, чтобы быть в состоянии получить адрес его прозрачно.

// could evaluate at compile time if __builtin_sin gets
// special treatment by the compiler
#define sin(x) __builtin_sin(x)

// parentheses avoid substitution by the macro
double (sin)(double arg) {
    return sin(arg); // uses the macro
}

int main() {
    // uses the macro
    printf("%f\n", sin(3.14));

    // uses the function
    double (*x)(double) = &sin;

    // uses the function
    printf("%f\n", (sin)(3.14));
}
27
ответ дан Johannes Schaub - litb 28 November 2019 в 06:00
поделиться

Преобразование их к конструкции языка для улучшения безопасности типов и отладки способности.

0
ответ дан JohnMcG 28 November 2019 в 06:00
поделиться

Когда я работаю над огромным c/c ++ вложенные структуры как та, используемая для 3GPP RRC/NBAP/RNSAP, я следую за этим приемом, чтобы заставить код выглядеть чистым.

struct leve1_1
{
  int data;

  struct level2
  {
    int data;

    struct level3
    {
      int data;
    } level_3_data;

  } level_2_data;

} level_1_data;

level_1_data.data = 100;

#define LEVEL_2 leve1_1_data.level_2_data
LEVEL_2.data = 200;

#define LEVEL_3 LEVEL_2.level_3_data
LEVEL_3.data = 300;

#undef LEVEL_2
#undef LEVEL_3

Это сделает жизнь легче в течение времени обслуживания.. также во время проектирования и код будет читаемо.

0
ответ дан Warrior 28 November 2019 в 06:00
поделиться

pthreads служебные макросы являются particularily впечатляющими, по моему скромному мнению.

0
ответ дан dsm 28 November 2019 в 06:00
поделиться

макрос BOOST_BINARY выполняет некоторый clevel обман препроцессора, чтобы дать C++ способность выразить числовые константы в двоичном файле. Это ограничено 0-255 как бы то ни было.

1
ответ дан Ferruccio 28 November 2019 в 06:00
поделиться

Большинство (все?) Платформы Поблочного тестирования C++ создаются на макросах. Мы используем UnitTest ++ . Проверьте его для наблюдения всех видов необычных макросов.

1
ответ дан Joe 28 November 2019 в 06:00
поделиться

Из проекта CrashRpt должны будьте обмануть для расширения макросов, и определяет:

#define WIDEN2(x) L ## x 
#define WIDEN(x) WIDEN2(x)
std::wstring BuildDate = std::wstring(WIDEN(__DATE__)) + L" " + WIDEN(__TIME__);
2
ответ дан Brian R. Bondy 28 November 2019 в 06:00
поделиться

При реализации сервера COM необходимо заботиться обо всех исключениях, которые код мог возможно выдать - разрешение исключению через границу метода COM будет часто разрушать вызывающее приложение.

скобки Методов полезны для этого. Существует открывающая скобка, которая является макросом, содержащим "попытку" и закрывающую скобку, которая содержит ряд "выгоды" es, обертывания исключений в ErrorInfo и создания HRESULTs.

2
ответ дан sharptooth 28 November 2019 в 06:00
поделиться

Я часто обертываю вещи как гидролокатор отладки в простом макросе, который позволяет ему быть скомпилированным из сборок конечных версий:

#ifdef DEBUG
#define D(s) do { s; } while(0)
#else
#define D(s) do {/**/} while(0)
#endif

Использование позже - обычно что-то как:

D(printf("level %d, condition %s\n", level, condition));

do{}while(0) идиома там для предотвращения проблем, которые могли бы следовать из случайного создания использования D(...) единственное содержание условного выражения или цикла. Вы не хотите, чтобы код как это означал неправильную вещь, в конце концов:

for(i=1;i<10;++i) D(printf("x[%d]=%f\n",i,x[i]));
SomeReallyExpensiveFunction(x);

, Если бы я мог бы заставить тот случай бросить ошибку, я был бы, но препроцессор должен был бы быть самим полным компилятором, чтобы сказать, что D() макрос был единственным содержанием тела цикла.

я - также большой поклонник утверждений времени компиляции. Моя формулировка немного отличается, но не имеет никаких реальных преимуществ перед другими, которых я видел. Ключ должен сформировать исключительно именованное определение типа, которое бросает ошибку, если утверждаемое условие является ложью, и не иначе. В cassert.h мы имеем:

/*! \brief Compile-time assertion.
 *
 *  Note that the cassert() macro generates no code, and hence need not
 *  be restricted to debug builds.  It does have the side-effect of
 *  declaring a type name with typedef.  For this reason, a unique
 *  number or string of legal identifier characters must be included
 *  with each invocation to avoid the attempt to redeclare a type.
 *
 *  A failed assertion will attempt to define a type that is an array
 *  of -1 integers, which will throw an error in any standards
 *  compliant compiler. The exact error is implementation defined, but
 *  since the defined type name includes the string "ASSERTION" it
 *  should trigger curiosity enough to lead the user to the assertion
 *  itself.
 *
 *  Because a typedef is used, cassert() may be used inside a function,
 *  class or struct definition as well as at file scope.
 */
#define cassert(x,i) typedef int ASSERTION_##i[(x)?1:-1]

И в некотором исходном файле, где угодно определение типа было бы законно:

#include "cassert.h"
...
cassert(sizeof(struct foo)==14, foo1);
...

получающееся сообщение об ошибке часто неясно, но будет содержать фрагмент идентификатора, позволяющего незаконную строку быть обнаруженной грубой силой.

я был виновен в использовании препроцессора в местах, где запись утилиты генерации кода, возможно, была предпочтительным ответом, во многом как код в другом ответе, который генерировал много шаблона на основе уникальных частей имени перечислимого участника. Это особенно удобно при записи большого количества связующего звена отправки сообщения, которое будет скомпилировано в C.

4
ответ дан RBerteig 28 November 2019 в 06:00
поделиться

Основное место я использую макросы, находится в моей собственной среде тестирования. Например, когда я хочу утверждать, что некоторый код должен бросить, я использую этот макрос:

#define MUST_THROW( expr )                       
  try {                                
    (expr);                              
    (myth_suite_).Fail( #expr +                    
            std::string( " should throw but didn't" ) );  
  }                                  
  catch( ... ) {                            
  }                                  

И использование это как это:

MUST_THROW( some_bogus_stuff() );
MUST_THROW( more_bogus_stuff() );

Единственное другое место я использую их, находится в объявлениях класса. У меня есть макрос:

#define CANNOT_COPY( cls )              \
  private:                              \
    cls( const cls & );                 \
    void operator=( const cls & )       \

, который я использую, чтобы определить, что класс не может быть скопирован (или присвоен):

class BankAccount {

    CANNOT_COPY( BankAccount );
    ....
};

это не делает ничего специального, но привлекает внимание народов и может легко разыскиваться.

6
ответ дан sth 28 November 2019 в 06:00
поделиться

Я верю Sean Barrett за этого забавного:

#ifndef blah
    #define blah(x) // something fun
    #include __FILE__
    #undef blah
#endif

#ifndef blah
    #define blah(x) // something else that is also fun
    #include __FILE__
    #undef blah
#endif

#ifdef blah
    blah(foo)
    blah(bar)
#endif

А hacky способ заставить препроцессор генерировать код для Вас на основе некоторой высокоуровневой структуры, которую можно выразить через макросы.

8
ответ дан 2 revs, 2 users 77% 28 November 2019 в 06:00
поделиться

Ведение журнала является одним из мест, где макросы особенно часто используются:

#define LOG(log) \
  if (!log.enabled()) {} \
  else log.getStream() << __FILE__ << "@" << __LINE__ << ": "


log_t errorlog;
...

LOG(errorlog) << "This doesn't look good:" << somedata;
7
ответ дан sth 28 November 2019 в 06:00
поделиться

Один из моих любимых приемов является способом передать переменное количество аргументов макросам, позже использоваться в вызывании подобных printf функций, например. Чтобы сделать это, я определяю, что макрос имеет только один параметр, и используйте его в органе по макросу без (), но передайте все параметры макросу в ((и)), таким образом, список похож на отдельный аргумент. Например,

#define TRACE( allargs) do { printf allargs; } while ( 0)
...
TRACE(( "%s %s\n", "Help", "me"));
8
ответ дан dmityugov 28 November 2019 в 06:00
поделиться

SHOW () для отладки:

#define SHOW(X) cout << # X " = " << (X) << endl

Двойная оценка для расширения трюка аргументов: (Например, используйте фактический номер строки, а не «__LINE __».)

    /* Use CONCATENATE_AGAIN to expand the arguments to CONCATENATE */
#define CONCATENATE(      x,y)  CONCATENATE_AGAIN(x,y)
#define CONCATENATE_AGAIN(x,y)  x ## y

Статические утверждения во время компиляции.
Например:

#define CONCATENATE_4(      a,b,c,d)  CONCATENATE_4_AGAIN(a,b,c,d)
#define CONCATENATE_4_AGAIN(a,b,c,d)  a ## b ## c ## d

    /* Creates a typedef that's legal/illegal depending on EXPRESSION.       *
     * Note that IDENTIFIER_TEXT is limited to "[a-zA-Z0-9_]*".              *
     * (This may be replaced by static_assert() in future revisions of C++.) */
#define STATIC_ASSERT( EXPRESSION, IDENTIFIER_TEXT)                     \
  typedef char CONCATENATE_4( static_assert____,      IDENTIFIER_TEXT,  \
                              ____failed_at_line____, __LINE__ )        \
            [ (EXPRESSION) ? 1 : -1 ]

Используется через:

typedef  int32_t  int4;

STATIC_ASSERT( sizeof(int4) == 4, sizeof_int4_equal_4 );

Инициализация экземпляра класса CodeLocation: (Сохранение файла / строки / функции с точки вызов - это можно сделать ТОЛЬКО * с помощью макроса или путем прямого доступа к макросам __FILE __ / __ LINE __ / etc в исходной точке.)

        /* Note:  Windows may have __FUNCTION__.  C99 defines __func__. */
#define CURRENT_CODE_LOCATION()  \
           CodeLocation( __PRETTY_FUNCTION__, __FILE__, __LINE__ )

Впоследствии используется MESSAGE / WARN / FAIL Макросы как удобный механизм печати исходного местоположения. Например:

#define WARN_IF_NAN(X)                                      \
  do                                                        \
  {                                                         \
    if ( isnan(X) != 0 )                                    \
      WARN( # X " is NaN (Floating Point NOT-A-NUMBER)" );  \
    if ( isinf(X) != 0 )                                    \
      WARN( # X " is INF (Floating Point INFINITY)" );      \
  } while ( false )

Утверждение / Разве что макросы. Вы можете передать любой токен, включая такие операторы, как '==', через макрос. Так конструкции как:

ASSERT( foo, ==, bar )

Или

UNLESS( foo, >=, 0, value=0; return false; );

являются законными. Утверждение / Если макросы не могут автоматически добавлять всякую полезную информацию, такую ​​как CodeLocation, отслеживание стека или корректное создание исключений / coredumping / exit.


Делать ошибки проще:

#define ERRNO_FORMAT  "errno= %d (\"%s\")"
#define ERRNO_ARGS    errno, strerror(errno)
#define ERRNO_STREAM  "errno= " << errno << " (\"" << strerror(errno) << "\") "

Например. printf («Ошибка открытия.» ERRNO_FORMAT, ERRNO_ARGS);

11
ответ дан 2 revs 28 November 2019 в 06:00
поделиться

Можно взглянуть на Повышение. Препроцессор для нахождения партии интересного использования препроцессора...

11
ответ дан sth 28 November 2019 в 06:00
поделиться

Существует также идиома X Macro, которая может быть полезна для СУХОЙ и простой генерации кода:

В заголовке gen.xa определена таблица с использованием макроса , еще не определенного :

/** 1st arg is type , 2nd is field name , 3rd is initial value , 4th is help */
GENX( int , "y" , 1 , "number of ..." );
GENX( float , "z" , 6.3 , "this value sets ..." );
GENX( std::string , "name" , "myname" , "name of ..." );

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

class X
{
public :

     void setDefaults()
     {
#define GENX( type , member , value , help )\
         member = value ;
#include "gen.x"
#undef GENX
     }

     void help( std::ostream & o )
     {
#define GENX( type , member , value , help )\
          o << #member << " : " << help << '\n' ;
#include "gen.x"
#undef GENX
     }

private :

#define GENX( type , member , value , help )\
     type member ;
#include "gen.x"
#undef GENX
}
14
ответ дан 2 revs, 2 users 99%florent_azcarate 28 November 2019 в 06:00
поделиться

Самый прохладный макрос: утверждайте, включайте защиту, __ ФАЙЛ __, __ СТРОКА __.
Избегают использования другого макроса в Вашем коде.

РЕДАКТИРОВАНИЕ:
макросы Использования только, когда у Вас нет легального решения w/o ими.

14
ответ дан bayda 28 November 2019 в 06:00
поделиться

Можно упростить повторяющиеся вещи, т. Е. перечислимые списки

enum {
  kOneEnum,
  kTwoEnum,
  kThreeEnum,
  kFourEnum
};

... и позже сделать переключение по структурированному пути

#define TEST( _v ) \
    case k ## _v ## Enum: \
      CallFunction ## _v(); \
      break;

switch (c) {
    TEST( One   );
    TEST( Two   );
    TEST( Three );
    TEST( Four  );
}

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

... или для проверки строк, чтобы получить правильное значение enum

int value = -1;
char *str = getstr();

#define TEST( _v ) \
    if (!strcmp(# _v, str)) \
        value = k ## _v ## Enum

TEST( One   );
TEST( Two   );
TEST( Three );
TEST( Four  );
3
ответ дан epatel 28 November 2019 в 06:00
поделиться
void _zero_or_die(int v, const char* filename, int line)
{
    if (v != 0)
    {
       fprintf(stderr, "error %s:%d\n", filename, line);
       exit(1);
    }
}

#define ZERO_OR_DIE_ for (int _i=1; _i == 1; _zero_or_die(_i, __FILE__, __LINE__)) _i=



ZERO_OR_DIE_   pipe(fd);
ZERO_OR_DIE_   close(0);
ZERO_OR_DIE_   sigaction(SIGSEGV, &sigact, NULL);
ZERO_OR_DIE_   pthread_mutex_lock(&mt);
ZERO_OR_DIE_   pthread_create(&pt, NULL, func, NULL);
0
ответ дан 28 November 2019 в 06:00
поделиться

На микроконтроллерах обычно отлаживают код с помощью UART, поскольку аппаратные точки останова имеют много недостатков.

Это простой макрос, который оказался очень полезным:

#define DEBUG_OUT(value) sprintf(uartTxBuf, "%s = 0x%04X\n", #value, value);\
                         puts_UART((uint16_t *) uartTxBuf)

Пример использования:

for (i=0; i < 4; i++)
{
    DEBUG_OUT(i);
    DEBUG_OUT(i % 3);
}

Полученный поток:

i = 0x0000
i % 3 = 0x0000
i = 0x0001
i % 3 = 0x0001
i = 0x0002
i % 3 = 0x0002
i = 0x0003
i % 3 = 0x0000

Да, это грубо и небезопасно. Он применяется только до тех пор, пока ошибка не будет изолирована, поэтому этот макрос не причинит вреда.

0
ответ дан 28 November 2019 в 06:00
поделиться