Jakie jest najgorsze nadużycie makr / preprocesorów w świecie rzeczywistym, z jakim się kiedykolwiek spotkałeś?


176

Jakie jest najgorsze nadużycie makr / preprocesorów w świecie rzeczywistym , z jakim kiedykolwiek się spotkałeś (prosimy o żadne wymyślone odpowiedzi IOCCC * haha ​​*)?

Dodaj krótki fragment lub historię, jeśli jest naprawdę zabawny. Celem jest nauczenie czegoś zamiast ciągłego mówienia ludziom „nigdy nie używaj makr”.


ps: Używałem wcześniej makr ... ale zwykle w końcu się ich pozbywam, gdy mam „prawdziwe” rozwiązanie (nawet jeśli prawdziwe rozwiązanie jest wbudowane, więc staje się podobne do makra).


Bonus: Podaj przykład, w którym makro było naprawdę lepsze niż rozwiązanie inne niż makro.

Powiązane pytanie: Kiedy makra C ++ są korzystne?


+1 za zwrócenie uwagi na szalejące nadużycia, jakich doznałem z rąk Makra.
i_am_jorf

37
#define true false // szczęśliwe debugowanie :)
n0rd

Wiki społeczności oznacza, że ​​nikt nie zyska (ani nie straci) reputacji w wyniku głosów w górę / w dół na to pytanie lub na jego odpowiedzi. Wiele osób postrzega takie pytania jako tani i łatwy sposób na zdobycie reputacji, więc jeśli oznaczysz je jako wiki społeczności, jest mniej prawdopodobne, że ludzie stracą kształt i zamkną go.
Graeme Perrow

2
„ludzie prawdopodobnie stracą kształt i zamkną się”: Czy sugerujesz, że nie chcesz żadnych humorystycznych / zabawnych treści przy przepełnieniu stosu?
Trevor Boyd Smith

2
Krótko mówiąc, preprocesor jest częścią języka i dlatego nie jest zły / zły w użyciu, tak jak wszystko inne.
Mr. Boy

Odpowiedzi:


410

Z pamięci wyglądało to mniej więcej tak:

#define RETURN(result) return (result);}

int myfunction1(args) {
    int x = 0;
    // do something
    RETURN(x)

int myfunction2(args) {
    int y = 0;
    // do something
    RETURN(y)

int myfunction3(args) {
    int z = 0;
    // do something
    RETURN(z)

Tak, zgadza się, żadnych nawiasów zamykających w żadnej funkcji. Podświetlanie składni było bałaganem, więc użył vi do edycji (nie vim, ma kolorowanie składni!)

Był rosyjskim programistą, który pracował głównie w języku asemblerowym. Był fanatykiem oszczędzania jak największej liczby bajtów, ponieważ wcześniej pracował nad systemami z bardzo ograniczoną pamięcią. "To było dla satelity. Tylko kilka bajtów, więc używamy każdego bajtu do wielu rzeczy." (trochę się bawiąc, ponownie wykorzystując bajty instrukcji maszynowych dla ich wartości liczbowych) Kiedy próbowałem dowiedzieć się, jakie rodzaje satelitów, udało mi się tylko uzyskać informację „Orbitujący satelita. Aby dostać się na orbitę”.

Miał dwa inne dziwactwa: wypukłe lusterko zamontowane nad monitorem „za to, żeby wiedzieć, kto patrzy” i sporadyczne nagłe wyjście z krzesła, aby zrobić szybkie dziesięć pompek. Tłumaczył ten ostatni jako "Kompilator znalazł błąd w kodzie. To jest kara".


87
„Kompilator znalazł błąd w kodzie. To jest kara”. !! Firma znalazła cię ... kara dla współpracowników!
Nauka

227
W sowieckiej Rosji program kompiluje CIEBIE!
Crashworks,

53
Kiedy przeczytałem o błędzie kompilatora „kara”, pierwszą rzeczą, o której pomyślałem, było „Zgredek musiał wyprasować ręce”.
Graeme Perrow

124
Myślę, że programiści (łącznie ze mną) byliby o wiele lepiej przygotowani, gdybyśmy wszyscy robili 10 pompek za każdym razem, gdy kompilator znalazł błąd w naszym kodzie. Może to również zmniejszyć częstość testowania przez kompilację.
MikeyB

5
Ten facet brzmi świetnie. Ale tak, nie rozumiem, jak to ma poprawić rozmiar kodu.
jalf

274

Mój najgorszy:

#define InterlockedIncrement(x) (x)++
#define InterlockedDecrement(x) (x)--

Spędziłem dwa dni mojego życia na poszukiwaniu wielowątkowego problemu z liczeniem referencyjnym COM, ponieważ jakiś idiota umieścił to w pliku nagłówkowym. Nie wspomnę o firmie, w której wtedy pracowałem.

Morał tej opowieści? Jeśli czegoś nie rozumiesz, przeczytaj dokumentację i dowiedz się o tym. Nie pozwól, żeby to odeszło.


146
@Joshua: Jeśli uruchomisz ten kod w środowisku wielowątkowym, możesz to zrobić nieumyślnie
1800 INFORMACJA

11
„Jeśli czegoś nie rozumiesz, przeczytaj dokumentację i dowiedz się o tym. Nie pozwól jej odejść”. - AMEN!
Paul Alexander,

2
@ 1800 Informacja: myślę, że po prostu straciłbyś głosy, dlatego nie mogę ci jednego dać; p
wkf

5
Wybacz mi jako programistę spoza C ++: czy głównym problemem jest to, że funkcja ochrony wątków jest konwertowana na funkcję bez ochrony wątków? Lub że InterlockedIncrement oczekuje wskaźnika, więc teraz zwiększysz wskaźnik zamiast tego, na co wskazuje? Lub oba?
Tim Pietzcker

38
Problem polega na tym, że InterlockedIncrement jest zwykle niepodzielną funkcją zdefiniowaną w interfejsie API systemu Windows. Więc kiedy ludzie wywołują InterlockedIncrement, spodziewają się wywołania funkcji, która ma być wykonana niepodzielnie. Zamiast tego ktoś zdefiniował makro o tej samej nazwie, które daje zwykły, nieatomowy przyrost
Jalf

166
#define ever (;;)
for ever { 
   ...
}

52
Wolę <#define forever for (;;)>, więc możesz pisać <forever {...}>
paxdiablo

ktoś, kogo poszedłem do szkoły z zagubionymi ocenami za EVER ... był zakrztuszony, jak to było w podręczniku :-)
TofuBeer

6
Czy sugestia Paxa nie pochodzi od K&R? Mimo wszystko, powiedziałbym, że nie jest to warte wysiłku.
Jon Ericson

Właściwie to wcale nie jest złe. Nie używam for (;;)idiomu, w przeciwnym razie natychmiast dodam to makro do mojego kodu.
AnT

1
@hayalci: W emacs lisp (i niektórych typowych implementacjach lisp) możesz, (defmacro ever ())a potem(require 'cl (ever))
Joe D

145
#include <iostream>
#define System S s;s
#define public
#define static
#define void int
#define main(x) main()
struct F{void println(char* s){std::cout << s << std::endl;}};
struct S{F out;};

public static void main(String[] args) {
  System.out.println("Hello World!");
}

Wyzwanie: czy ktoś może to zrobić z mniejszą liczbą definicji i struktur? ;-)


19
właśnie napisałeś konwerter java-to-c! okropny!
Andreas Petersson

25
Zgłoszone jako „obraźliwe”. (Żartuję!)
Annika Backstrom

40
To jest albo ohydnie piękne, albo pięknie ohydne.
Chris Lutz

38
@Mark - deklaruje publici static as nothing, unieważnia `jako int, i main(x)jako main(), więc public static void main(String[] args)zamienia się w int main(). Następnie Systemzamienia się w S s;s, więc System.out.println("Hello World!");zamienia się w S s; s.out.println("Hello World!");który wywołuje printlnfunkcję w Fstrukturze w Sstrukturze.
Chris Lutz

2
Spójrz na to: mailcom.com/ioccc/chia/chia.c (pobierz i skompiluj)
Roberto Bonvallet

130
#define private public

Robiłem to już wcześniej. Czasami wystarczy zmodyfikować zmienną składową lub nadpisać funkcję w kodzie innej firmy, której nie można zmienić - a oni nie dostarczyli ci akcesorium.
Michael Kristofik,

30
wow, jeśli chodzi o testy jednostkowe, może to być nawet przydatne, nawet jeśli duchy projektowania obiektów będą cię nawiedzać w nocy.
Epaga

12
Hmmm, niezdefiniowane zachowanie, łatwe naruszenie zasady jednej definicji, potencjalne różnice w układzie. Tak, to jest zwycięzca.
David Thornley

10
Dzięki temu mogę uzyskać dostęp do rzeczy prywatnych i publicznych, ale nie do rzeczy chronionych, i nie mogę uzyskać dostępu do rzeczy między classsłowem kluczowym a pierwszym modyfikatorem dostępu.
Ken Bloom

3
@Ken:#define class struct #define protected public
Yakov Galka

107
#define if while

To był żart, który ktoś zagrał, a osoby dotknięte tym problemem nie uznały tego za zabawne


22
#define while if byłoby jeszcze bardziej podstępne.
starblue

7
Powinniśmy wyjaśnić Twoje oświadczenie. Ludzie, których to dotyczy, nie uznali tego za zabawne . :-)
Andrew Shepherd

6
Kiedy odrabiałem prace domowe, często robiłem tego typu rzeczy celowo, aby zirytować moich nauczycieli.
pyon

15
To dobry dowcip, ale nie skompiluje się, jeśli są jakieś instrukcje „inne”. Odkryłem, że #define if (x) if (true) jest najbardziej efektywne.
Grafika Noob

32
Zawsze wolałem #define sizeof (x) rand ()
Jon

106

Ohydne:

#define begin {
#define end }
/* and so on */

Poważnie, jeśli chcesz kodować w Pascalu, kup kompilator Pascala, nie niszcz pięknego języka C.


45
Teraz zastanawiam się, jakie języki mogę symulować za pomocą wystarczająco sprytnego pliku nagłówkowego.
Bill the Lizard

47
C nie jest piękny. To raczej brzydkie.
rlbond

27
Jej piękno tkwi w prostocie. Mówi się, że łączy szybkość asemblera z czytelnością… asemblera :-) Wolę go od rozdętego C ++ (chociaż wolę Javę w mojej codziennej pracy ze względu na jej ogromną bibliotekę).
paxdiablo

9
Nie naprawdę. Znajdź oryginalne źródło Bourne'a dla powłoki Bourne'a. Zrobił dokładnie to, żeby dostać jakiś bękart podobny do ALGOLA bałagan.
RBerteig

3
# zdefiniować DO for (int _i = 0; _i <= 1; ++ _ i) {if (_i == 1) //// PRZERWANIE WIERSZA //// # zdefiniować JEŻELI (stan); if (! (cond)) przerwa; } //// PRZERWANIE WIERSZA //// DO printf ("a") IF (1 == 2);
Adrian Panasiuk

93

`` Architekt '', bardzo skromny facet, znasz ten typ, miał:

#define retrun return

ponieważ lubił szybko pisać. Chirurg mózgu lubił krzyczeć na ludzi, którzy byli od niego mądrzejsi (czyli prawie wszyscy), i groził, że użyje na nich swojego czarnego pasa.


Robię tę literówkę tak bardzo, że faktycznie to rozważałem.
Joshua

4
raczej naucz swojego edytora, aby automatycznie zamieniał powtórkę na powrót. Zrobiłem takie hakery na moim kliencie IRC, przynajmniej
Tetha

1
Hej, myślę, że pracowałem też z tym „architektem”. W końcu został przekwalifikowany na starszego architekta, kiedy potrzebował uspokojenia ego.
BIBD,

1
W bash zmieniłem definicję „rn” na „rm”, ponieważ nie mogłem pisać, a przeglądarka grup dyskusyjnych „rn” potrzebowała 5 minut na uruchomienie i połączenie z serwerem.
Martin Beckett

2
Nie możesz po prostu otworzyć nowego terminala (lub przełączyć się na inny VT) i zrobić killall rn?
Joe D

69

Prawdziwy świat? MSVC ma makra w minmax.h, wywoływane maxi min, które powodują błąd kompilatora za każdym razem, gdy zamierzam użyć std::numeric_limits<T>::max()funkcji standardowej .


2
Ach, tak, dlatego miałem specjalny nagłówek z # undef przywracającym zdrowie psychiczne po tych specyficznych dla MS ...
Pontus Gagge

3
Rozwiązany za pomocą (std :: numeric_limits <T> :: max) () Ale tak, dość denerwujące.
rlbond

36
Dodaj NOMINMAX do właściwości projektu w C / C ++ -> Preprocessor -> Preprocessor Definitions.
mattnewport

18
Te makra istniały w nagłówkach MS dłużej niż min i max i były w C ++ Standard Library.
Richard

4
Jest jeszcze gorzej, gdy cztery inne zewnętrzne zależności również definiują własne wartości min / max, o różnym stopniu podstępności, od makr w źle ujętych w nawiasach po dobrze napisane szablony, a jedna z nich musi po prostu uniemożliwić niezdefiniowanie lub w inny sposób je pomiń ... Jednak w mojej książce język jest w 50% winny.
Roman Starkov

58

Połączenie składni Pascala i francuskich słów kluczowych:

#define debut {
#define fin }
#define si if(
#define alors ){
#define sinon }else{
#define finsi }

36
#define zut_alors exit (-1)
MikeyB,

4
To jest niesamowite i rozśmieszyło mnie głośno. Więc to jest w zasadzie zlokalizowana francuska wersja Basic'a ​​zaimplementowana w C?
Bobby,

56

Raymond Chen ma naprawdę dobrą opinię przeciwko używaniu makr kontroli przepływu . Jego najlepszy przykład pochodzi prosto z oryginalnego kodu źródłowego powłoki Bourne'a:

ADDRESS alloc(nbytes)
    POS     nbytes;
{
    REG POS rbytes = round(nbytes+BYTESPERWORD,BYTESPERWORD);

    LOOP    INT     c=0;
    REG BLKPTR  p = blokp;
    REG BLKPTR  q;
    REP IF !busy(p)
        THEN    WHILE !busy(q = p->word) DO p->word = q->word OD
        IF ADR(q)-ADR(p) >= rbytes
        THEN    blokp = BLK(ADR(p)+rbytes);
            IF q > blokp
            THEN    blokp->word = p->word;
            FI
            p->word=BLK(Rcheat(blokp)|BUSY);
            return(ADR(p+1));
        FI
        FI
        q = p; p = BLK(Rcheat(p->word)&~BUSY);
    PER p>q ORF (c++)==0 DONE
    addblok(rbytes);
    POOL
}

2
Dwie kwestie: po pierwsze, ta pasta zepsuła oryginalne wcięcie. Po drugie, kod wygląda dobrze na to, czym jest: Unix C z lat 70. XX wieku autorstwa zagorzałego fana Algol-68. Skoro _ dlaczego szczęściarz może wyrazić siebie w dziwacznym stylu, dlaczego nie może Steve Bourne? Oczywiście ktoś skazany na utrzymanie tego, kto nie zna Algola 68, może nie docenić tej szansy na poszerzenie własnych upodobań.
Darius Bacon

Myślę, że to może być żartem Steve'a Bourne'a, a nie sugerowany styl programowania
Martin Beckett

2
Widziałem if... else... elif... fii case... esacwcześniej (w tym samym języku, który Bourne wymyślił dla sh), ale loop... poolto prawdziwy klejnot.
hobbs

54

Chciałbym zgłosić na konkurs perełkę o nazwie chaos-pp , która implementuje język funkcjonalny za pomocą makr preprocesora.

Jednym z przykładów jest obliczenie 500-tej liczby Fibonacciego w całości przez preprocesor:

Oryginalny kod przed preprocesorem wygląda następująco:

int main(void) {
   printf
     ("The 500th Fibonacci number is "
      ORDER_PP(8stringize(8to_lit(8fib(8nat(5,0,0)))))
      ".\n");
   return 0;
}

przygotowując plik otrzymujemy następujący wynik (po dość długim oczekiwaniu):

$ cpp -I../inc fibonacci.c 2>/dev/null | tail
  return fib_iter(n, 0, 1);
}
# 63 "fibonacci.c"
int main(void) {
   printf
     ("The 500th Fibonacci number is "
      "139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125"
      ".\n");
   return 0;
}

1
Możesz pobrać kod z CVS i rzucić okiem. Kilka szczegółów na ten temat zamieściłem jakiś czas temu w moim poście na blogu, kiedy się na niego natknąłem : bnpcs.blogspot.com/2009/02/ ... Gdyby nie problem z debugowaniem powstałego kodu (problem z bardzo długimi liniami, jeśli są generowane przez taki „język”), mógłby być nawet użyteczny jako praktyczny generator kodu dla C.
Andrew Y

Mogę sobie tylko wyobrazić, że kompilacja trwa wiecznie
Paul Fultz II

52

Bezpośrednio z Qt:

#define slots   /* */
#define signals /* */

Naprawdę miło jest współdziałać z innymi bibliotekami jako boost :: signal ... Na przykład, w Qt jest wiele innych, które tworzą zabawnie wyglądający kod, taki jak:

class X : public QObject {
   Q_OBJECT
private slots:
   //...
public signals:
   //...
};

I to jest C ++ ... ale nagle:

boost::signals::trackable

Nie jest już poprawna w C ++.


5
:) Jest to więc makro, które bez powodu psuje inne biblioteki. To nawet lepsze niż się spodziewałem :)
David Rodríguez - dribeas

38
Qt jest bardzo terytorialne i będzie brutalnie atakować inne biblioteki, które próbują zająć jego przestrzeń nazw :)
Jeremy Friesner

21
Niestety Qt atakuje biblioteki poza swoją przestrzenią nazw przy użyciu makr
David Rodríguez - dribeas

7
Na szczęście boost :: signal2 naprawił ten problem;)
bdonlan

9
Użyj Q_SIGNALS i Q_SLOTS, jeśli boisz się tej interakcji.
Tadeusz A. Kadłubowski

50

Windows.h ma wiele funkcji, które nadużywały makr.


MrValdez jest zirytowany makro GetObject znalezionym w Windows.h

Makro GetObject zmienia funkcję GetObject () w GetObjectA () lub GetObjectW () (w zależności od tego, czy kompilacja jest kompilowana odpowiednio w formacie innym niż Unicode i Unicode)

MrValdez nie lubi robić przed linią funkcji GetObject

#undef GetObject

Object *GetObject()

Alternatywą jest zmiana nazwy funkcji na inną, np. GetGameObject ()


jdkoftinoff w komentarzach znalazł to: Problem polega na tym, że wszystkie funkcje Windows API są makrami.

Adam Rosenfield wspomniał, że problemy można naprawić, definiując NOGDI, WIN32_LEAN_AND_MEAN, NOMINMAX itp. Przed dołączeniem windows.h do usunięcia problemów.


3
Możesz to pominąć, ale # zdefiniować NOGDI przed dołączeniem windows.h, oczywiście pod warunkiem, że nie musisz używać żadnej z różnych funkcji GDI. Istnieje wiele innych makr, takich jak WIN32_LEAN_AND_MEAN, NOMINMAX itp., Które uniemożliwiają zdefiniowanie lub uwzględnienie innych rzeczy.
Adam Rosenfield,

1
GetObject to całkiem ogólna nazwa funkcji. Być może mógłbyś użyć bardziej opisowej nazwy, biorąc pod uwagę kontekst, aby uniknąć kolizji. Jednak jest to całkiem zły przypadek makro.
strager

1
To dość denerwujące, że win32 ma wszystkie makra do konwersji nazw API na FooA i FooW. Mamy problem z SendMessage.
i_am_jorf

6
Problem polega na tym, że wszystkie funkcje API systemu Windows są makrami. Jednym, który mnie ugryzł, był GetTickCount (). Ponieważ większość swojego programowania wykonuję poza oknami, znalazłem wszystkie definicje w nagłówkach okien, a następnie stworzyłem własny plik dołączający, który zdefiniował je wszystkie, aby wcześniej sprawdzić zgodność.
jdkoftinoff

12
Myślę, że mamy zwycięzcę. To prawdziwy świat, absurdalnie zły pomysł, który wpłynął na ogromną liczbę niewinnych programistów. Ktokolwiek jest odpowiedzialny za ten klejnot w firmie Microsoft, powinien zostać uznany za zbrodniarza wojennego ... Najlepsze jest to, że Microsoft nie zastanawiał się dwa razy nad używaniem tak niesamowicie popularnych nazw, takich jak GetObject, SendMessage czy CreateWindow.
jalf

45
#define return if (std::random(1000) < 2) throw std::exception(); else return

to jest po prostu takie złe. Jest losowy, co oznacza, że ​​odpala w różnych miejscach przez cały czas, zmienia instrukcję return, która zwykle zawiera kod, który może sam zawieść, zmienia niewinnie wyglądające słowo kluczowe, którego nigdy nie będziesz podejrzany i używa wyjątek od standardowej przestrzeni, więc nie będziesz próbował przeszukiwać źródeł, aby znaleźć ich źródło. Po prostu genialne.


4
Właśnie przetestowałem ten, przynajmniej nie kompiluje się domyślnie z powodu braku dołączenia dla losowego, a wtedy jest czerwony. Jeśli jednak przypadkowo włączysz dołączenie, sytuacja się pogorszy - VC ++ 2010 oznacza to nadal jako słowo kluczowe i nie wyświetla podpowiedzi rozwijania makr, więc IDE nie pomaga w znalezieniu tego: - /
OregonGhost

Kocham to! Czysty geniusz. Wyobraź sobie, jak dobrze możesz wyglądać, gdy "Debuguj" tę aplikację, gdy nikomu się to nie udało.
brice

36

Współpracownik i ja znaleźliśmy te dwie perełki w części naszego kodu do przesyłania strumieniowego obiektów. Te makra zostały utworzone w KAŻDYM POJEDYNCZYM pliku klasy, który wykonywał przesyłanie strumieniowe. Nie tylko ten ohydny kod jest rozlany po całej naszej bazie kodu, ale kiedy skontaktowaliśmy się w tej sprawie z oryginalnym autorem, napisał on 7-stronicowy artykuł na naszej wewnętrznej wiki, broniąc tego jako jedynego możliwego sposobu osiągnięcia tego, co próbował tutaj zrobić.

Nie trzeba dodawać, że od tego czasu został on refaktoryzowany i nie jest już używany w naszej bazie kodu.

Nie zrażaj się wyróżnionymi słowami kluczowymi. To WSZYSTKO jest makrem

#define DECLARE_MODIFICATION_REQUEST_PACKET( T )                                                \
namespace NameSpace                                                                     \
{                                                                                       \
                                                                                        \
class T##ElementModificationRequestPacket;                                                          \
}                                                                                       \
                                                                                        \
DECLARE_STREAMING_TEMPLATES( IMPEXP_COMMON_TEMPLATE_DECLARE, NameSpace::ElementModificationRequestPacket<T>, OtherNameSpace::NetPacketBase )    \
DLLIMPEXP_COMMON_TEMPLATE_DECLARE( NameSpace::ElementModificationRequestPacket<T> )     \
DECLARE_AUTOGENERATION_TEMPLATES( DLLIMPEXP_COMMON_TEMPLATE_DECLARE, NameSpace::T##ModificationRequestPacket, NameSpace::ElementModificationRequestPacket<T> )      \
                                                                                        \
namespace NameSpace {                                                                   \
class DLLIMPEXP_COMMON T##ModificationRequestPacket : public ElementModificationRequestPacket<T>\
{                                                                                       \
public:                                                                                 \
    T##ModificationRequestPacket( NetBase * pParent )                                   \
    : ElementModificationRequestPacket<T>( pParent ), m_Gen() {}                            \
                                                                                        \
    T##ModificationRequestPacket( NetBase * pParent,                                    \
                            Action          eAction,                                    \
                            const T &   rT )                                            \
    : ElementModificationRequestPacket<T>( pParent, eAction, rT ), m_Gen() {}               \
                                                                                        \
    T##ModificationRequestPacket( const T##ModificationRequestPacket & rhs )                        \
    : ElementModificationRequestPacket<T>( rhs ), m_Gen() {}                                \
                                                                                        \
    virtual                     ~T##ModificationRequestPacket( void ) {}                        \
                                                                                        \
    virtual Uint32          GetPacketTypeID( void ) const                           \
    {                                                                                   \
        return Net::T##_Modification_REQUEST_PACKET;                                        \
    }                                                                                   \
                                                                                        \
    virtual OtherNameSpace::ClassID GetClassID ( void ) const                           \
    {                                                                                   \
        return OtherNameSpace::NetBase::GenerateHeader( OtherNameSpace::ID__LICENSING,  \
                                                         Net::T##_Modification_REQUEST_PACKET );    \
    }                                                                                   \
                                                                                        \
    virtual T##ModificationRequestPacket * Create( void ) const                             \
    { return new T##ModificationRequestPacket( m_pParent ); }                                   \
                                                                                        \
    T##ModificationRequestPacket() {}                                                           \
                                                                                        \
protected:                                                                              \
    OtherNameSpace::ObjectAutogeneration<T##ModificationRequestPacket> m_Gen;                       \
                                                                                        \
    friend class OtherNameSpace::StreamingBase::StreamingClassInfoT<T##ModificationRequestPacket >;                     \
    OtherNameSpace::StreamingBase::Streaming<T##ModificationRequestPacket, ElementModificationRequestPacket<T> >    m_Stream;   \
                                                                                        \
};                                                                                      \
}                                                                                       \
DLLIMPEXP_COMMON_TEMPLATE_DECLARE( ThirdNameSpace::ListenerBase<const NameSpace::T##ModificationRequestPacket> )            \
DLLIMPEXP_COMMON_TEMPLATE_DECLARE( ThirdNameSpace::BroadcasterT<const NameSpace::T##ModificationRequestPacket> )            \
typedef  ThirdNameSpace::BroadcasterT<const T##ModificationRequestPacket>  T##ModifiedBroadcaster;



#define IMPLEMENT_MODIFICATION_REQUEST_PACKET( T )                                                                  \
DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE( NameSpace::ElementModificationRequestPacket<T> )                         \
DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE( ThirdNameSpace::ListenerBase<const NameSpace::T##ModificationRequestPacket> )        \
DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE( ThirdNameSpace::BroadcasterT<const NameSpace::T##ModificationRequestPacket> )        \
INSTANTIATE_STREAMING_TEMPLATES( DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE, NameSpace::ElementModificationRequestPacket<T>, OtherNameSpace::NetPacketBase ) \
INSTANTIATE_AUTOGENERATION_TEMPLATES( DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE, NameSpace::T##ModificationRequestPacket, NameSpace::ElementModificationRequestPacket<T> )

Aktualizacja (17 grudnia 2009):

Więcej dobrych wiadomości dotyczących tego ohydnego autora makr. Od sierpnia pracownik odpowiedzialny za tę potworność został zwolniony.


3
on oczywiście nigdy nie słyszał o: „Debugowanie jest po pierwsze dwa razy trudniejsze niż pisanie kodu. Dlatego jeśli piszesz kod tak sprytnie, jak to tylko możliwe, z definicji nie jesteś wystarczająco inteligentny, aby go debugować”. -Brian W. Kernighan
Trevor Boyd Smith

33

Sam wykonałem następujące czynności i myślę, że czegoś się z tego nauczyłem.

Mniej więcej w 1992 roku napisałem małego interpretera Lispa. Nie został zaimplementowany w normalnym C, ale w interpretowanym języku podobnym do C. Ten język podobny do języka C wykorzystywał jednak standardowy preprocesor C.

Oczywiście interpreter Lispa zawierał funkcje car , który jest używany w Lispie do zwracania pierwszego elementu listy, oraz cdr , który zwraca resztę listy. Zostały zaimplementowane w następujący sposób:

LISPID car(LISPID id) {
    CHECK_CONS("car", 1, id);
    return cons_cars[id - CONS_OFFSET];
} /* car */

LISPID cdr(LISPID id) {
    CHECK_CONS("cdr", 1, id);
    return cons_cdrs[id - CONS_OFFSET];
} /* cdr */

(Dane były przechowywane w tablicach, ponieważ nie było struktur. CONS_OFFSET to stała 1000).

car i cdr są często używane w Lisp i są krótkie, a ponieważ wywołania funkcji nie były zbyt szybkie w języku implementacji, zoptymalizowałem swój kod, implementując te dwie funkcje Lisp jako makra:

#define car(id) (CHECK_CONS("car", 1, (id)), cons_cars[(id) - CONS_OFFSET])
#define cdr(id) (CHECK_CONS("car", 1, (id)), cons_cdrs[(id) - CONS_OFFSET])

CHECK_CONS sprawdza, czy jego argument w rzeczywistości jest listą, a ponieważ ten jest również często używany w interpretatorze i jest krótki, napisałem go również jako makro:

#define CHECK_CONS(fun, pos, arg)   \
    (!IS_CONS(arg) ?        \
        LISP_ERROR("Arg " + pos + " to " + fun +    \
                   " must be a list: " + lispid2string(arg)) : 0)

IS_CONS i LISP_ERROR były również często używane, więc zrobiłem z nich również makra:

#define IS_CONS(id) \
    (   intp(id) && (id) >= CONS_OFFSET     \
     && ((id) - CONS_OFFSET) < sizeof(cons_cars))

#define LISP_ERROR(str)     (throw((str) + "\n"))

Wydaje się rozsądne?

Ale w takim razie dlaczego cały system się zawiesił w tej linii:

id2 = car(car(car(car((id1))));

Długo pracowałem, aby znaleźć problem, aż w końcu sprawdziłem, do czego ta krótka linia została rozszerzona przez preprocesor. Został rozszerzony do wiersza o długości 31370 znaków, który tutaj podzieliłem na wiersze (z nich 502) dla przejrzystości:

id2 = ((!(intp( (((!(intp( (((!(intp( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
&& ( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000]))) && ( (((!(intp(
(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000]))) >= 1000 && ((
(((!(intp( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000]))) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (((!(intp( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1))
&& ( (id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars))

18
I optimized my code by implementing those [..] functions as macros- słynne ostatnie słowa ...
BlueRaja - Danny Pflughoeft

3
Podobnych nadużyć popełniłem we wczesnych wersjach mojego interpretera PostScript. Push i pop były funkcjami, które były tak ważne, że powinny być makrami . Jednak utworzenie wyrażenia zawierającego więcej niż jeden z nich prowadzi do nieokreślonego zachowania. Niezdefiniowane zachowanie jest wychwytywane tylko podczas kompilacji przy -O3. A przy -O3 wersje funkcji i tak byłyby wstawione.
luser droog

29

Kiedyś musiałem przenieść aplikację C z unixa do Windowsa, której specyfika pozostanie bez nazwy, aby chronić winnych. Facet, który to napisał, był profesorem nieprzyzwyczajonym do pisania kodu produkcyjnego i najwyraźniej przybył do C z innego języka. Zdarza się też, że angielski nie był jego pierwszym językiem, choć kraj, z którego pochodził, większość ludzi mówi nim całkiem dobrze.

Jego aplikacja w dużym stopniu wykorzystywała preprocesor, aby przekształcić język C w format, który mógł lepiej zrozumieć. Ale makra, których używał najczęściej, zostały zdefiniowane w pliku nagłówkowym o nazwie „Thing.h” (poważnie), który zawierał następujące elementy:

#define I  Any void_me
#define thou  Any void_thee
#define iam(klas)  klas me = (klas) void_me
#define thouart(klas)  klas thee = (klas) void_thee
#define my  me ->
#define thy  thee ->
#define his  him ->
#define our  my methods ->
#define your  thy methods ->

... którego następnie używał do pisania potworności, takich jak następujące:

void Thing_setName (I, const char *name) {
iam (Thing);
if (name != my name) {
    Melder_free (my name);
    my name = Melder_wcsdup (name);
    }
    our nameChanged (me);
}

void Thing_overrideClass (I, void *klas) {
iam (Thing);
my methods = (Thing_Table)klas;
if (! ((Thing_Table) klas) -> destroy)
    ((Thing_Table) klas) -> _initialize (klas);
}

Cały projekt (~ 60 000 LOC) został napisany w podobnym stylu - marco hell, dziwne nazwy, staroangielski żargon itp. Na szczęście udało nam się wyrzucić kod, ponieważ znalazłem bibliotekę OSS, która wykonywała ten sam algorytm dziesiątki razy szybciej.

(Skopiowałem i zredagowałem tę odpowiedź, którą pierwotnie udzieliłem na to pytanie ).


3
Jestem raczej oczarowany zaborczym i archaicznym angielskim, mimo wszystko zgadzam się, że kod wygląda okropnie.
Darius Bacon

27

Najgorsze, jakie kiedykolwiek spotkałem, było w produkcie zawierającym pakiet plików wykonywalnych, w przypadku których wyznaczony lider techniczny nie rozgryzł bibliotek.

Zamiast tego miał zestawy plików, które zostały udostępnione w kilku folderach Visual Source Safe. Wtedy zdał sobie sprawę, że muszą zachowywać się nieco inaczej dla każdej aplikacji.

Istnieje kilka kroków refaktoryzacji, które możesz zastosować tutaj.

Zamiast tego użył #ifdefs

   void DisplayLoadError()
   {
   #if defined __TIMETABLE_EDITOR
   MessageBox("Timetable Editor failed to load the correct timetable", MB_ERROR);
   #else if defined __SCHEDULESET_EDITOR
   MessageBox("Schedule Set Editor faied to load the correct Schedule Set", MB_ERROR);
   #else if defined __ROSTER_EDITOR
   MessageBox("Roster Editor failed to load the correct Roster", MB_ERROR);
   #endif
   }

17

Użycie preprocesora LINE do generowania unikalnego identyfikatora dla wiadomości przesyłanych przez sieć:

NetworkMessages.h

#define MSG_LOGIN  __LINE__
#define MSG_LOGOUT __LINE__
#define MSG_CHAT   __LINE__

Oto przykład, w którym makro naprawdę było lepsze niż rozwiązanie inne niż makro:

W rozwiązaniach innych niż makra, funkcje i zmienne muszą być zbudowane, aby śledzić, jaki identyfikator jest wiadomość. Deweloper może, ale nie musi, skomplikować śledzenie identyfikatora wiadomości, podczas gdy jest to łatwiejsze do odczytania i debugowania.

Ponadto łatwiej jest dodawać nowe wiadomości, po prostu dodając wiadomość do źródła.

Wadą tej sytuacji jest to, że plik musi być zawarty w całym kodzie używającym komunikatów. Czas kompilacji wydłużałby się przy każdej edycji wiadomości.


8
Wersje mogą być ze sobą niekompatybilne (niedobre!). Dlaczego wyliczenie nie wystarczyło?
strager

Zarówno to, jak i Enum mają dokładnie ten sam problem z niekompatybilnością.
MrValdez

17
Teraz przychodzę i sortuję #defines ... i zmienia się protokół. Albo zdobywam religię Doxygen i dokumentuję wszystkie kody wiadomości, a protokół się zmienia. Przynajmniej wyliczenie jest stabilne przy ostatniej zmianie.
RBerteig

3
@MrValdez, utrzymywanie bloku wyliczeń w porządku jest mniej restrykcyjne niż przechowywanie definicji w tych samych wierszach względem początku pliku.
peterchen

Wiem, że to stary post, ale czy to w ogóle działa? Chodzi mi o to, że #define po prostu zamieni stałe komunikatu na LINE i dopiero wtedy LINE zostanie rozwinięte do numeru wiersza, więc za każdym razem, gdy użyjemy tej samej stałej w różnych wierszach - zmieni się (na bieżący numer wiersza)?
XzKto

16

Jeden dość zły przykład:

#ifdef __cplusplus
#define class _vclass
#endif

Pozwala to na strukturę C, która zawiera zmienną składową wywoływaną classdo obsługi przez kompilator C ++. Istnieją dwa nagłówki z tą konstrukcją; jeden z nich zawiera również '#undef class' na końcu, a drugi nie.


1
Dlatego Objective-C używa @classzamiast class.

14

W ciągu jednego roku Międzynarodowego Konkursu Zakamuflowanego Kodowania Kodu był wpis, w którym cały program był:

P

Z zastrzeżeniem, że możesz zdefiniować P w pliku makefile dowolny program.

O ile pamiętam, wygrał w jednej z kategorii, aw następnym roku pojawiła się reguła zabraniająca tego stylu zgłaszania się.

(Edycja: sześć miesięcy później czy coś w tym stylu ... Jestem pewien, że kwestia "Brak IOCCC" nie była głównym pytaniem, kiedy to pisałem ...)


12

Pewnego dnia się nudziłem i bawiłem się klockami w Objective-C ...

#define Lambda(var, body) [^ id(id (var)) { return (body);} copy]
#define Call(f, arg) ((id(^)(id))(f))(arg)
#define Int(num) [NSNumber numberWithInteger:(num)]
#define Mult(a, b) Int([(a) integerValue] * [(b) integerValue])
#define Add(a, b) Int([(a) integerValue] + [(b) integerValue])
#define Sub1(n) Int([(n) integerValue] - 1)
#define Add1(n) Int([(n) integerValue] + 1)
#define If(cond, thenblock, elseblock) ([(cond) integerValue] ? (thenblock) : (elseblock))
#define Cons(car, cdr_) [[ConsType alloc] initWithCar:(car) cdr:(cdr_)]
#define Car(list) [(list) car]
#define Cdr(list) [(list) cdr]
#define Define(var, value) id var = (value)
#define Nullq(value) Int(value == nil)

zezwalając na „interesujące” rzeczy, takie jak:

Define(Y, Lambda(f, Call(Lambda(x, Call(x, x)),
                         Lambda(x, Call(f, Lambda(y, Call(Call(x, x), y)))))));
Define(AlmostTotal, Lambda(f, Lambda(list, If(Nullq(list), Int(0),
                                              Add(Car(list), Call(f, Cdr(list)))))));
Define(Total, Call(Y, AlmostTotal));
Print(Call(Total, Cons(Int(4), Cons(Int(5), Cons(Int(8), nil)))));

(niektóre definicje funkcji i klas nie zostały pokazane ze względu na zwięzłość)


"Pewnego dnia się nudziłem" ostatnie słowa słynnego dewelopera :)
Richard J. Ross III

11

Najgorszy, jaki widziałem, to brak użycia :-)

Ktoś napisał strcpy (myślę, że to było to ... ponad 10 lat temu) wewnątrz metody (ponieważ nie chciał narzutu wywołania strcpy ... westchnienie).

Doszli do wniosku, że nie będzie działać dla znaków japońskich, więc dodali na początku „jeśli”, aby wykonać ASCII lub Unicode. W tym momencie kod był długi na ekran ... prawdopodobnie zabijając spójność pamięci podręcznej i wymazując jego rzekome oszczędności na wstawianie kodu.

Kod był identyczny z zapisem dla typów (więc należało użyć makra).

Oczywiście strcpy, które napisali, było znacznie wolniejsze niż ręcznie dostrojony asembler, który był w standardowej bibliotece ...

Oczywiście, gdyby zrobili to wszystko jako makro, można by je zastąpić wywołaniem strcpy ...

Oczywiście odszedłem z firmy (nie bezpośrednio z tego powodu ...)


The code was identical save for the types (so should have used a macro).Nie, powinien był użyć szablonu.
BlueRaja - Danny Pflughoeft

1
Powinien był użyć wbudowanego strcpy! (i to był kod w C, a nie C ++, więc nie ma szablonów) :-P
TofuBeer

Przedwczesna optymalizacja jest źródłem wszelkiego zła.
Hubert Kario

11

Obowiązkowe

#define FOR  for

i

#define ONE  1
#define TWO  2
...

Kto wiedział?


5
Ale-ale-ale BEZ LITERÓW W KODZIE! ;)
Bernard

nadal są to literały mon, należy je nazywać według celu / intencji, a nie alternatywnego symbolu. Kod COBOL, o którym słyszałem, zrobili zmienną 5 = 5, a później mieli kod mówiący set 5 = 10 ... ludzie byli naprawdę zaskoczeni, kiedy zrobili var + 5 i otrzymali var + 10.
Greg Domjan

1
Nigdy o tym nie słyszałem z COBOL, tylko z FORTRANEM. COBOL ma oczywiście ZERO, ZEROS i ZEROES jako zarezerwowane słowa, wszystkie oznaczają dokładnie to samo co 0.
David Thornley,

Znacznie lepsze niż „#define ONE 0”. Jeśli chcesz się pośmiać, poszukaj tego w Internecie i zdziw się niezerową liczbą trafień.
reuben

11
#define TRUE 0 // dumbass

Osoba, która to zrobiła, wyjaśniła się kilka lat później - większość (jeśli nie wszystkie) funkcji biblioteki C zwraca 0 jako wskazówkę, że wszystko poszło dobrze. Chciał więc móc pisać kod taki jak:

if (memcpy(buffer, packet, BUFFER_SIZE) == TRUE) {
; // rape that packet
}

Nie trzeba dodawać, że nikt w naszym zespole (tester lub programista) nigdy nie odważył się ponownie spojrzeć na jego kod.


1
obwiniam funkcje biblioteki C o to, że 0 „wszystko jest w porządku”: P
RCIX

6
Dlaczego nie zadeklarować czegoś takiego #define FLAG_SUCCESS 0?
pyon

11

Utrzymuję kod, który zawiera makra. Zatem funkcja będzie miała etykietę na końcu, ale w kodzie funkcji nie będzie widocznego przejścia. Co gorsza, makro znajduje się na końcu innych instrukcji, zwykle poza ekranem, chyba że przewijasz w poziomie.

#define CHECK_ERROR if (!SomeCondition) goto Cleanup

void SomeFunction() 
{ 
    SomeLongFunctionName(ParamOne, ParamTwo, ParamThree, ParamFour); CHECK_ERROR  
    //SomeOtherCode  
    Cleanup:    
   //Cleanup code  
}

Co gorsza, makra ukrywają zarówno gotoinstrukcje, jak i definicje etykiet docelowych. Całkowicie magiczne.
reuben

Cierpiałem na to - ale makra wyglądały jak wywołania funkcji.
Jonathan Leffler

10
#include <iostream>
#define public_static_void_main(x) int main()
#define System_out_println(x) std::cout << x << std::endl

public_static_void_main(String[] args) {
  System_out_println("Hello World!");
}

3
A TY chciałeś napisać środowisko wykonawcze. Zobacz, ile czasu zaoszczędziłem!
Bernard,

4
@Trevor: Tak ... inteligentni nadal używają Javy. biegnie do ukrycia
Michael Myers

Jeśli umieścisz [] po args zamiast przed i "#define String int argc, char *", zostanie skompilowany (niestety).
Adam Rosenfield,

16
Ten drugi wolę bardziej. Ten pokazuje coś zbliżonego do pisania w Javie za pomocą kilku makr. Drugi pokazuje, że dokładna Java została napisana z mnóstwem podstępnych makr i struktur z elementami składowymi funkcji. Pierwszy był tanim dowcipem, drugi zaś wyszukanym i przemyślanym dowcipem.
Chris Lutz,

10

Kolega z klasy, który nie zrozumiał zasad dotyczących magicznych liczb:
#define TWO_HUNDRED_AND_EIGHTY_THREE_POINT_ONE 283.1


9

ASA - http://www.ingber.com/#ASA

Naprawdę musisz go pobrać, aby to docenić. Cały przepływ pracy jest określany przez makra. Jest całkowicie nieczytelny. Jako przykład -

 if (asa_open == FALSE) {
asa_open = TRUE;
++number_asa_open;
#if ASA_PRINT
if (number_asa_open == 1) {
  /* open the output file */
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
#if ASA_SAVE
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
#else
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "w");
#endif
  }
#else /* USER_ASA_OUT */
  if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
#if ASA_SAVE
    ptr_asa_out = fopen (ASA_OUT, "a");
#else
    ptr_asa_out = fopen (ASA_OUT, "w");
#endif
  }
#endif /* USER_ASA_OUT */
} else {
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
  }
#else
  if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (ASA_OUT, "a");
  }
#endif
  fprintf (ptr_asa_out, "\n\n\t\t number_asa_open = %d\n",
           number_asa_open);
}
#endif /* ASA_PRINT */
} else {
++recursive_asa_open;
#if ASA_PRINT
if (recursive_asa_open == 1) {
  /* open the output file */
#if ASA_SAVE
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
  }
#else
  if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (ASA_OUT, "a");
  }
#endif
#else /* ASA_SAVE */
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {

itd itd.

A to tylko konfiguracja opcji. cały program jest taki.


2
O mój Boże ... Myślę, że mam zawroty głowy.
Michael Foukarakis
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.