Jakie są niektóre sztuczki, których mogę używać z makrami? [zamknięte]

W naszym kodzie starszym, jak również w naszym nowoczesnym kodzie, używamy makr do wykonywania sprytnych rozwiązań, takich jak generacje kodu itp. Wykorzystujemy zarówno operatory #, jak i ##.

Jestem ciekaw, jak inni programiści używają makr do robienia fajnych rzeczy, jeśli w ogóle ich używają.

Author: 7 revs, 4 users 75%Sasha , 2009-03-16

25 answers

W języku C, często definiuje się makra, które robią pewne rzeczy, pobierając dosłowny argument, a jednocześnie definiują funkcje, aby móc przejrzyście uzyskać jego adres.

// 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));
}
 25
Author: Johannes Schaub - litb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-16 14:40:21

Najfajniejsze makro to: assert, include, _ _ FILE__, _ _ LINE__.
Unikaj używania innych makr w kodzie.

EDIT:
Używaj makr tylko wtedy, gdy nie masz legalnego rozwiązania.

 14
Author: bayda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-16 14:27:33

Istnieje również idiom Makro X, który może być przydatny do generowania suchego i prostego kodu:

Definiuje się w nagłówku gen. x rodzaj tabeli używając makra jeszcze nie zdefiniowanego :

/** 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 ..." );

Wtedy może używać go w różnych miejscach definiując go dla każdego # include z zazwyczaj inną definicją:

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
}
 13
Author: 2 revs, 2 users 99%florent_azcarate,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-24 20:38:37

Możesz rzucić okiem na Boost.Preprocesor aby znaleźć wiele ciekawych zastosowań preprocesora...

 11
Author: sth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-16 13:53:34

SHOW () do debugowania:

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

Double-evaluation, aby rozwinąć argumenty trick: (np. użyj rzeczywistego numeru linii, a nie " _ _ 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

Statyczne twierdzenia o czasie kompilacji.
np.:

#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 ]

Użyte przez:

typedef  int32_t  int4;

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

Inicjalizacja instancji klasy CodeLocation: (Przechowywanie pliku/linii / funkcji z punktu wywołania -- można to *tylko* zrobić za pomocą makra lub poprzez bezpośredni dostęp do makr _ _ pliku _ _ / _ _ linii _ _ / etc w źródło.)

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

Następnie używany przez makra MESSAGE / WARN / FAIL jako wygodny mechanizm drukowania lokalizacji źródła. Na przykład:

#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 / Unless makra. Możesz przekazać dowolny token, w tym operatory takie jak"==", przez makro. Konstruuje się tak:

ASSERT( foo, ==, bar )

Lub

UNLESS( foo, >=, 0, value=0; return false; );
Są legalne. Assert / Unless makra mogą automatycznie dodawać wszelkiego rodzaju przydatne informacje, takie jak CodeLocation, stack traces, lub rzucanie WYJĄTKÓW / coredumping / wychodząc z wdziękiem.

Tworzenie errno prostsze:

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

Np. printf ("Open failed. "ERRNO_FORMAT, ERRNO_ARGS);

 9
Author: Mr.Ree,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-16 17:09:47

Jedną z moich ulubionych sztuczek jest sposób przekazywania zmiennej liczby argumentów do makr, które będą później użyte w wywołaniu funkcji podobnych do printf na przykład. Aby to zrobić, zaznaczam, że makro ma tylko jeden parametr i używam go w ciele makra without (), ale przekazuję wszystkie parametry do makra in (( and)), więc lista wygląda jak pojedynczy argument. Na przykład,

#define TRACE( allargs) do { printf allargs; } while ( 0)
...
TRACE(( "%s %s\n", "Help", "me"));
 8
Author: dmityugov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-16 15:01:16

Logowanie jest jednym z miejsc, gdzie makra są szczególnie często używane:

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


log_t errorlog;
...

LOG(errorlog) << "This doesn't look good:" << somedata;
 7
Author: sth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-16 14:21:59

Zasługuję na Seana Barretta za tę zabawną:

#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

Hakerski sposób, aby preprocesor wygenerował kod dla Ciebie w oparciu o jakąś strukturę wyższego poziomu, którą możesz wyrazić za pomocą makr.

 7
Author: MSN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-26 16:17:20

Głównym miejscem, w którym używam makr, jest mój własny framework testowy. Na przykład, gdy chcę stwierdzić, że jakiś kod musi rzucić, używam tego makra:

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

I użyj go tak:

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

Jedyne miejsce, w którym ich używam, to deklaracje klas. Mam makro:

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

Którego używam do określenia, że klasa nie może być skopiowana (lub przypisana):

class BankAccount {

    CANNOT_COPY( BankAccount );
    ....
};
To nie robi nic specjalnego, ale przyciąga uwagę ludzi i można go łatwo wyszukać.
 6
Author: sth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-30 18:10:06

Do wbudowanego kodu, fajny trik z embeddedgurus.com umożliwia obsługę wartości binarnych:

B8(01010101) // 85
B16(10101010,01010101) // 43,605
B32(10000000,11111111,10101010,01010101) // 2,164,238,93

To osiąga podobne cele, jak poprzednia odpowiedź @Ferruccio na temat BOOST_BINARY, choć nieco Rozszerzona.

Oto kod (copy ' N wklejony, nie testowany, zobacz link po więcej szczegółów)

// Internal Macros
#define HEX__(n) 0x##n##LU
#define B8__(x) ((x&0x0000000FLU)?1:0) \
  +((x&0x000000F0LU)?2:0) \
  +((x&0x00000F00LU)?4:0) \
  +((x&0x0000F000LU)?8:0) \
  +((x&0x000F0000LU)?16:0) \
  +((x&0x00F00000LU)?32:0) \
  +((x&0x0F000000LU)?64:0) \
  +((x&0xF0000000LU)?128:0)

// User-visible Macros
#define B8(d) ((unsigned char)B8__(HEX__(d)))
#define B16(dmsb,dlsb) (((unsigned short)B8(dmsb)<<8) + B8(dlsb))
#define B32(dmsb,db2,db3,dlsb) \
  (((unsigned long)B8(dmsb)<<24) \
  + ((unsigned long)B8(db2)<<16) \
  + ((unsigned long)B8(db3)<<8) \
  + B8(dlsb))
Lubię makra. Tak dużo zabawy podczas debugowania !
 5
Author: kebs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-09 14:55:56

Często zawijam takie rzeczy jak debug sonar w proste makro, które pozwala na skompilowanie go z wersji kompilacji:

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

Użycie później jest zazwyczaj czymś w rodzaju:

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

Idiom do{}while(0) służy do unikania problemów, które mogą wynikać z przypadkowego użycia D(...) jedynej zawartości pętli warunkowej lub pętli. Nie chcesz, żeby taki kod oznaczał coś złego, w końcu:

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

Gdybym mógł sprawić, że ten przypadek spowoduje błąd, zrobiłbym to, ale preprocesor zrobiłby musi być pełny kompilator, aby powiedzieć, że makro D() było jedyną zawartością ciała pętli.

Jestem również wielkim fanem twierdzeń w czasie kompilacji. Moja formuła jest nieco inna, ale nie ma realnych zalet w stosunku do innych, które widziałem. Kluczem jest utworzenie unikalnie nazwanego typedef, który wyświetla błąd, jeśli podany warunek jest fałszywy, a nie inny. In cassert.H mamy:

/*! \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]

I w jakimś pliku źródłowym, gdziekolwiek typedef byłby legalny:

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

Wynik komunikat o błędzie jest często niejasny, ale będzie zawierał fragment identyfikatora umożliwiający wykrycie naruszającej linii przez brute force.

Byłem winny używania preprocesora w miejscach, gdzie pisanie narzędzia do generowania kodu mogło być preferowaną odpowiedzią, podobnie jak kod w innej odpowiedzi, który generował wiele płyt kotłowych na podstawie unikalnych części nazwy członka enum. Jest to szczególnie przydatne przy pisaniu dużej ilości wiadomości-klej wysyłkowy do skompilowania w C.

 4
Author: RBerteig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-16 23:44:36

Można uprościć rzeczy powtarzalne dla ie. listy enum

enum {
  kOneEnum,
  kTwoEnum,
  kThreeEnum,
  kFourEnum
};

...a później wykonaj przypadek przełącznika w sposób zorganizowany

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

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

Notatka: jasne, że można to zrobić za pomocą tablicy wskaźników funkcji, ale otwiera się to dla nieco większej elastyczności, aby dodać parametry i również użyć rozszerzeń ciągów z pojedynczym Hashem.

...lub testować na łańcuchach, aby uzyskać właściwą wartość 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
Author: epatel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-16 21:25:35

Literały Struct z wartościami domyślnymi (które nie są zerowe), używając makr wariacyjnych C99

struct Example {
   int from;
   int to;
   const char *name;
}

#define EXAMPLE(...) ((struct Example){.from=0, .to=INT_MAX, .name="", __VA_ARGS__})

Użycie EXAMPLE(.name="test") używa wartości domyślnych, z wyjątkiem jawnego nadpisania name. To zacienienie z późniejszymi wzmiankami o tym samym członie jest dobrze zdefiniowane w standardzie.

 3
Author: u0b34a0f6ae,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-31 12:36:31

Można używać makr do definiowania tej samej funkcjonalności z różnymi typami danych. Na przykład:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>

#define DEFINE_BITS_STR(name, type)               \
char *bits_str_##name(type value)                 \
{                                                 \
    int len = sizeof(type) * CHAR_BIT;            \
    char *result;                                 \
    type n;                                       \
    int i;                                        \
                                                  \
    result = (char *)calloc(len+1, sizeof(type)); \
    if(result == NULL)                            \
        return NULL;                              \
                                                  \
    memset(result, '0', len);                     \
    result[len] = 0x00;                           \
                                                  \
    n = value;                                    \
    i = len;                                      \
    while(n)                                      \
    {                                             \
        if(n & 1)                                 \
            result[i] = '1';                      \
                                                  \
        n >>= 1;                                  \
        --i;                                      \
    }                                             \
                                                  \
    return result;                                \
}

DEFINE_BITS_STR(uchar, unsigned char)
DEFINE_BITS_STR(uint, unsigned int)
DEFINE_BITS_STR(int, unsigned int)

int main()
{
    unsigned char value1 = 134;
    unsigned int value2 = 232899;
    int value3 = 255;
    char *ret;

    ret = bits_str_uchar(value1);
    printf("%d: %s\n", value1, ret);

    ret = bits_str_uint(value2);
    printf("%d: %s\n", value2, ret);

    ret = bits_str_int(value3);
    printf("%d: %s\n", value3, ret);

    return 1;
}

W tym przykładzie definiuje się trzy funkcje (bits_str_uchar(), bits_str_uint(), bits_str_int()) które obsługują trzy różne typy danych(unsigned char, unsigned int, int). Jednak all zwraca łańcuch zawierający bity przekazanej wartości.

 3
Author: vicentazo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-31 15:26:06

Kiedy implementujesz serwer COM, musisz zadbać o wszystkie wyjątki, które twój kod może wyrzucić - przepuszczenie wyjątku przez granicę metody COM często spowoduje awarię wywołującej aplikacji.

Metody nawiasy są do tego przydatne. Jest nawias otwierający, który jest makrem zawierającym " try "i nawias zamykający, który zawiera zestaw"catch" es, owijanie WYJĄTKÓW w ErrorInfo i tworzenie HRESULTs.

 2
Author: sharptooth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-16 13:49:41

Z projektu CrashRpt, potrzeba tricka, aby rozszerzyć makra i zdefiniować:

#define WIDEN2(x) L ## x 
#define WIDEN(x) WIDEN2(x)
std::wstring BuildDate = std::wstring(WIDEN(__DATE__)) + L" " + WIDEN(__TIME__);
 2
Author: Brian R. Bondy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-16 13:55:39

Most (all?) C++ Unit Testing Framework jest zbudowany na makrach. Używamy UnitTest++. Sprawdź, aby zobaczyć wszelkiego rodzaju fantazyjne makra.

 1
Author: Joe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-16 13:59:39

Makro BOOST_BINARY wykonuje pewne sztuczki przed procesorem, aby dać C++ możliwość wyrażania stałych liczbowych w postaci binarnej. Jest jednak ograniczona do 0-255.

 1
Author: Ferruccio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-16 14:00:58

Makra narzędzia pthreads są szczególnie imponujące IMHO.

 0
Author: dsm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-16 14:07:25

Kiedy pracuję nad ogromnymi strukturami zagnieżdżonymi w c/C++, takimi jak ta używana w 3GPP RRC/NBAP / RNSAP, podążam za tą sztuczką, aby Kod wyglądał czysto.

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
To ułatwi życie w czasie konserwacji..również w czasie projektowania i Kod będzie czytelny.
 0
Author: Warrior,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-16 14:11:40

Konwersja ich do konstrukcji języka w celu poprawy bezpieczeństwa typów i możliwości debugowania.

 0
Author: JohnMcG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-16 20:50:46
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
Author: Adrian Panasiuk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-28 08:41:08

W mikro kontrolerach często debuguje się kod za pomocą UART, ponieważ sprzętowe punkty przerwania mają wiele wad.

Jest to proste makro, które okazało się bardzo przydatne:

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

Przykład użycia:

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

Otrzymany strumień:

i = 0x0000
i % 3 = 0x0000
i = 0x0001
i % 3 = 0x0001
i = 0x0002
i % 3 = 0x0002
i = 0x0003
i % 3 = 0x0000
Tak, jest surowy i niebezpieczny. Jest on stosowany tylko do momentu wyizolowania błędu, więc to makro nie szkodzi.
 0
Author: Josip,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-30 08:52:25

Często tego używam. Mam nagłówek debug.h zdefiniowany w następujący sposób:

#ifndef DEBUG_H
#define DEBUG_H
    #ifdef DEBUG
    #define debuf if(1)
    #else
    #define debug if(0)
    #endif
#endif

A potem:

debug {
   printf("message from debug!");
}

Jeśli Chcesz otrzymać "message from debug!" wiadomość, skompiluj za pomocą:

gcc -D DEBUG foo.c

Inaczej nic się nie stanie. Gcc jest bardzo inteligentnym kompilatorem. Jeśli DEBUG nie jest zdefiniowany, wygenerowany if(0) (martwy kod) zostanie usunięty z kodu z włączonymi optymalizacjami.

Nadal możesz zrobić więcej:

debug 
{
   pritnf("I'm in debug mode!\n");
} 
else 
{
  printf("I'm not in debug mode\n");
}

Kilka dni temu widziałem język programowania D zapewnia funkcję bardzo podobne.

Jeśli uważasz powyższe bez kontekstu, możesz zdefiniować myśli jako

#define in_debug if(1)
#define not_debug else

A następnie

in_debug {
  printf("I'm in debug mode!");
}
not_debug {
  printf("Not in debug mode!");
}
 0
Author: Jack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-02 21:20:03

W makrach bardzo łatwo jest kontrolować przepływ , ponieważ jest to tylko zastępowanie tekstu. Oto przykład z pętlą for:

#include <stdio.h>

#define loop(i,x) for(i=0; i<x; i++)

int main(int argc, char *argv[])
{
    int i;
    int x = 5;
    loop(i, x)
    {
        printf("%d", i); // Output: 01234
    } 
    return 0;
} 
 -1
Author: alexpinho98,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-20 10:42:28