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?
c++
c
macros
preprocessor
Trevor Boyd Smith
źródło
źródło
Odpowiedzi:
Z pamięci wyglądało to mniej więcej tak:
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".
źródło
Mój najgorszy:
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.
źródło
źródło
for (;;)
idiomu, w przeciwnym razie natychmiast dodam to makro do mojego kodu.(defmacro ever ())
a potem(require 'cl (ever))
Wyzwanie: czy ktoś może to zrobić z mniejszą liczbą definicji i struktur? ;-)
źródło
public
istatic as nothing,
unieważnia `jakoint
, imain(x)
jakomain()
, więcpublic static void main(String[] args)
zamienia się wint main()
. NastępnieSystem
zamienia się wS s;s
, więcSystem.out.println("Hello World!");
zamienia się wS s; s.out.println("Hello World!");
który wywołujeprintln
funkcję wF
strukturze wS
strukturze.źródło
class
słowem kluczowym a pierwszym modyfikatorem dostępu.#define class struct #define protected public
To był żart, który ktoś zagrał, a osoby dotknięte tym problemem nie uznały tego za zabawne
źródło
Ohydne:
Poważnie, jeśli chcesz kodować w Pascalu, kup kompilator Pascala, nie niszcz pięknego języka C.
źródło
`` Architekt '', bardzo skromny facet, znasz ten typ, miał:
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.
źródło
killall rn
?Prawdziwy świat? MSVC ma makra w minmax.h, wywoływane
max
imin
, które powodują błąd kompilatora za każdym razem, gdy zamierzam użyćstd::numeric_limits<T>::max()
funkcji standardowej .źródło
Połączenie składni Pascala i francuskich słów kluczowych:
źródło
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:
źródło
if
...else
...elif
...fi
icase
...esac
wcześniej (w tym samym języku, który Bourne wymyślił dla sh), aleloop
...pool
to prawdziwy klejnot.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:
przygotowując plik otrzymujemy następujący wynik (po dość długim oczekiwaniu):
źródło
Bezpośrednio z Qt:
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:
I to jest C ++ ... ale nagle:
Nie jest już poprawna w C ++.
źródło
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
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.
źródło
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.
źródło
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
Aktualizacja (17 grudnia 2009):
Więcej dobrych wiadomości dotyczących tego ohydnego autora makr. Od sierpnia pracownik odpowiedzialny za tę potworność został zwolniony.
źródło
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:
(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:
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:
IS_CONS i LISP_ERROR były również często używane, więc zrobiłem z nich również makra:
Wydaje się rozsądne?
Ale w takim razie dlaczego cały system się zawiesił w tej linii:
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:
źródło
I optimized my code by implementing those [..] functions as macros
- słynne ostatnie słowa ...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:
... którego następnie używał do pisania potworności, takich jak następujące:
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 ).
źródło
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
źródło
Użycie preprocesora LINE do generowania unikalnego identyfikatora dla wiadomości przesyłanych przez sieć:
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.
źródło
Jeden dość zły przykład:
Pozwala to na strukturę C, która zawiera zmienną składową wywoływaną
class
do 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.źródło
@class
zamiastclass
.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 ...)
źródło
Pewnego dnia się nudziłem i bawiłem się klockami w Objective-C ...
zezwalając na „interesujące” rzeczy, takie jak:
(niektóre definicje funkcji i klas nie zostały pokazane ze względu na zwięzłość)
źródło
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 ...)
źródło
The code was identical save for the types (so should have used a macro).
Nie, powinien był użyć szablonu.Obowiązkowe
i
Kto wiedział?
źródło
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:
Nie trzeba dodawać, że nikt w naszym zespole (tester lub programista) nigdy nie odważył się ponownie spojrzeć na jego kod.
źródło
#define FLAG_SUCCESS 0
?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.
źródło
goto
instrukcje, jak i definicje etykiet docelowych. Całkowicie magiczne.źródło
Kolega z klasy, który nie zrozumiał zasad dotyczących magicznych liczb:
#define TWO_HUNDRED_AND_EIGHTY_THREE_POINT_ONE 283.1
źródło
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 -
itd itd.
A to tylko konfiguracja opcji. cały program jest taki.
źródło