Dlaczego warto używać makr w C? [duplikat]

to pytanie ma już odpowiedzi tutaj : Zamknięte 11 lat temu .

Możliwy duplikat:
do czego przydatne są makra C?

Co kilka miesięcy mam swędzenie iść uczyć się trochę C że mój gówniany college Edukacja programistyczna nigdy nie była uwzględniona. Dziś to makra. Moje podstawowe zrozumienie makr jest to proste wyszukiwanie i zastępowanie, które dzieje się w kodzie przed do jego kompilacji. Mam problem ze zrozumieniemDlaczego używasz makr. Większość podstawowych przykładów, na które patrzę, to coś w stylu

TEST(a,%d);
#define TEST(a,b) printf(" The value of " #a " = " #b " \n", a)

//which expands to 
printf(" The value of a = %d \n",a);

(przykład z tutaj )

Z mojego punktu widzenia dla początkujących, wydaje się, że zdefiniowanie nowej funkcji dałoby takie same wyniki. Widzę. jak historycznie makra przydałyby się do szybkiego modyfikowania wielu źródeł w dniach przed łatwym wyszukiwaniem i zastępowaniem, ale coś mi mówi, że brakuje mi jakiegoś większego punktu.

Jakie przydatne rzeczy mogą Dla ciebie zrobić makra?

 50
Author: Community, 2009-08-31

11 answers

Jednym z powodów jest to, że do C99 słowo kluczowe inline nie było standardem w języku C. W ten sposób makra pozwoliły na wbudowanie małych funkcji. Działają również w pewien sposób jak szablony, tj. nie musisz określać typów w definicji makra np:

#define MAX(x,y) ((x) > (y) ? (x) : (y))

To makro jest zgodne z liczbami całkowitymi, podwójnymi, pływającymi itp.

 48
Author: DeusAduro,
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-31 16:38:29

To nie jest wyszukiwanie i zastępowanie, to rozszerzenie tokena. Makra C są tym, czym jest każdy inny rodzaj makra w świecie komputerów: sposobem na napisanie czegoś krótkiego i prostego i automatyczne przekształcenie go w coś dłuższego i bardziej skomplikowanego.

Jednym z powodów użycia makr jest wydajność. Są one sposobem na wyeliminowanie narzutu wywołania funkcji, ponieważ są zawsze rozszerzane in-line, W przeciwieństwie do słowa kluczowego "inline", które jest często ignorowaną podpowiedzią dla kompilatora, oraz nawet nie istniał (w standardzie) przed C99. Na przykład Zobacz rodzinę makr FD_ używanych w połączeniu z zestawami fd_ używanymi przez select i pselect. Te fd_sety to tak naprawdę tylko bitsety, a makra fd_ ukrywają operacje bitowe. Irytujące byłoby wypisywanie bitów za każdym razem, a wywołanie funkcji byłoby dużym obciążeniem dla tak szybkiej operacji, gdyby nie było wbudowane.

Również makra mogą robić pewne rzeczy, których funkcje nie mogą. Rozważ wklejanie tokenów. Ponieważ preprocesor działa przed kompilatorem, może tworzyć nowe identyfikatory dla kompilatora. Może to dać ci skrócony sposób tworzenia wielu podobnych definicji, np.

#define DEF_PAIR_OF(dtype) \
  typedef struct pair_of_##dtype { \
       dtype first; \
       dtype second; \
  } pair_of_##dtype##_t 

 DEF_PAIR_OF(int);
 DEF_PAIR_OF(double);
 DEF_PAIR_OF(MyStruct);
 /* etc */

Inną rzeczą, która może zrobić, że funkcja nie może zmienić informacji o czasie kompilacji w informacje o uruchomieniu:

#ifdef DEBUG
#define REPORT_PTR_VALUE(v) printf("Pointer %s points to %p\n", #v, v)
#else 
#define REPORT_PTR_VALUE(v)
#endif

void someFunction(const int* reallyCoolPointer) {
  REPORT_PTR_VALUE(reallyCoolPointer);
  /* Other code */
}

Nie ma możliwości, aby funkcja mogła używać nazwy swojego parametru w swoim wyjściu, tak jak makro can. To również demonstruje kompilowanie kodu debugowania dla release builds.

 69
Author: Tyler McHenry,
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-31 17:01:24

Makra są rozwijane w czasie kompilacji. Masz rację, że są one często nadużywane, ale klasycznym przykładem w C byłoby posiadanie makra do pisania wiadomości debugowania, które (gdy tryb debugowania jest wyłączony w czasie kompilacji) nie generuje żadnego kodu, więc nie powoduje spowolnienia.

 16
Author: Mike McQuaid,
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-31 16:38:41

Czasami chcesz zrobić logowanie, ale tylko w trybie debugowania. Więc piszesz coś w stylu:

#ifdef DEBUG
#define LOG_MSG(x) printf(x);
#else
#define LOG_MSG(X)
#endif

Czasami po prostu chcesz coś wyłączyć lub włączyć na podstawie przełącznika czasu kompilacji. Na przykład, moja firma robi co-branding naszego produktu i partnerzy proszą, aby wyłączyć rzeczy. Więc zrobimy coś w stylu:

#ifndef SPECIAL_PARTNER_BUILD
    DoSomethingReallyAwesome();
#endif

Następnie buduj za pomocą-DSPECIAL_PARTNER_BUILD, gdy dajesz partnerowi krople.

Wśród wielu innych możliwych powodów.

Czasami po prostu chcesz zapisać pisanie rzeczy, które robisz w kółko. Niektórzy ludzie posuwają się za daleko (kaszel MFC kaszel ) i piszą w makrach, co odpowiada ich własnemu językowi, aby usunąć trudne API. To sprawia, że debugowanie jest cholernym koszmarem.

 12
Author: i_am_jorf,
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-31 16:44:04

Makra mogą mieć wiele różnych zastosowań innych niż funkcje podobne do rzeczy.

Bardzo przydatne jest używanie makr do wszystkiego, co związane jest z magiczną liczbą lub ciągiem znaków.

#define MY_MAGIC_NUM 57

/*MY_MAGIC_NUM used all through out the code*/
 6
Author: lillq,
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-31 16:41:19

Makra C mogą generować kod podczas kompilacji. Może to być (ab)używane do skutecznego tworzenia języków specyficznych dla domeny z nowymi słowami kluczowymi i zachowaniami.

Jednym z moich ulubionych przykładów jest metoda Simona Tathama implementowania coroutines W C poprzez makra. Najprostsze zaimplementowane makro to:
#define crBegin static int state=0; switch(state) { case 0:
Tak, z niezrównaną klamrą. Inne makra to naprawią.
 5
Author: Dour High Arch,
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
2019-08-29 15:55:30

Użyliśmy tego typu makra w naszym kodzie:

// convenience macros for implementing field setter/getter functions
#ifndef CREATE_GET_SET
#define CREATE_GET_SET(PREFIX, FIELD_NAME,FIELD_DATATYPE) \
  protected:\
    FIELD_DATATYPE PREFIX ## FIELD_NAME;\
  public:\
  inline FIELD_DATATYPE get ## _ ## FIELD_NAME(void) const\
  { \
    return(PREFIX ## FIELD_NAME); \
  } \
  inline void set ## _ ## FIELD_NAME(FIELD_DATATYPE p) \
  { \
    PREFIX ## FIELD_NAME = p; \
  }
#endif

Wewnątrz klasy / struktury można zdefiniować zmienną:

CREATE_GET_SET(_, id, unsigned int);

To zdefiniuje Twoją zmienną i utworzy ogólny getter / setter dla kodu. To po prostu sprawia, że czystsze, spójne generowanie kodu dla get / set. Oczywiście, możesz to wszystko zapisać, ale to dużo kodu typu boilerplate uwaga: to tylko jedno z kilku makr. Nie wysłałem ich wszystkich. Nie dałbyś Rady powiedzieć "char *" w ten sposób (gdzie chcesz Zestaw strncpy lub strcpy danych). To było tylko proste demo tego, co można zrobić z makrem i kilkoma prostymi typami.

 3
Author: jmq,
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-31 17:46:05

W scenariuszach performance intense można używać makr do tworzenia" automatycznego " rozwijania pętli. Współczesne Kompilatory prawdopodobnie wykonują z tym lepszą pracę, ale kiedyś była to przydatna aplikacja.

 1
Author: korona,
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-31 16:40:02

Kompilator często zna szczegóły dotyczące docelowej maszyny, więc można użyć kompilacji warunkowej, aby mieć jeden kawałek kodu dla dużych procesorów endian i drugi dla małych procesorów endian. Dzięki temu kod nie jest nadęty kodem zaprojektowanym dla innego procesora.

Podobny przypadek ma miejsce, gdy masz kod asemblera dla jednego konkretnego systemu, ale kod C dla innych systemów.

 1
Author: Nosredna,
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-31 16:56:49

Myślę, że największą zaletą jest użycie jako "plik ustawień"

#define USE_FAST_AGORHITM
//#define USE_SLOW_ONE

I globalne "stałe"

#define MAX_NUMBER_OF_USERS 100000

Są programy napisane głównie w makrach (Sprawdź dla przykład implementacji AES Briana Gladmana http://www.gladman.me.uk/cryptography_technology/index.php )

 1
Author: Luka Rahne,
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-08-19 08:50:17

W makrach kod funkcji jest wstawiany do strumienia kodu wywołującego. Może to, w zależności od wielu innych rzeczy, poprawić wydajność, ponieważ optymalizator może proceduralnie zintegrować wywołany kod - zoptymalizować wywołany kod do wywołującego Ale uważaj, ponieważ na makrach typy argumentów nie są sprawdzane. Dobrym odniesieniem do funkcji inline (jeśli używasz również C++) i trochę makr jest. http://www.parashift.com/c++ - faq-lite / inline-functions.html#faq-9.5

 0
Author: Diego Dias,
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-31 16:47:29