xion.log » if (false) { }

if (false) { }

2010-05-22 16:49

Jeśli widzieliśmy już w swoim wystarczająco dużą ilość kodu w C lub C++, to istnieje pewna szansa, że natrafiliśmy na konstrukcję znaną jaką do-while(false). Występuje ona w dwóch wersjach. W pierwszej jest to właściwie goto w przebraniu – dzięki otoczeniu jakiegoś fragmentu kodu taką “pętlą” sprawiamy, że instrukcja break będzie powodowała skok tuż za nią. To pozwala na “wyjście” z danego fragmentu kodu np. wtedy, gdy wystąpi w nim jakiś błąd – oczywiście przy założeniu, że w środku nie ma kolejnej pętli lub switcha ;)
O drugiej wersji pisałem kilkanaście miesięcy temu. Jej zastosowaniem są makra preprocesora zawierająca kilka instrukcji; zamknięcie ich w do-while(false) zamiast w zwykły blok kodu ({ }) gwarantuje nam brak błędów składniowych niezależnie od miejsca użycia takiego makra.

Widać więc, że pętla z zawsze fałszywym warunkiem ma – mimo wszystko – jakieś zastosowanie… A co z analogicznym ifem? Czy if(false) ma jakieś sensowne zastosowanie poza ukazywaniem, że osoba używająca takiej konstrukcji do wyłączania kodu z kompilacji zapomniała o istnieniu dyrektywy #if, że o komentarzach nie wspomnę?…
Okazuje się, że jednak ma – przynajmniej mi dało się takowe zastosowanie znaleźć. Chcąc je zaprezentować, zacznę od takiego oto ciągu ifów:

  1. if (s == "foo") DoSth1(z);
  2. else if (s == "bar") DoSth2(x, y);
  3. else if (s == "baz") DoSth3();

który w założeniu może być oczywiście dowolnie długi i niekoniecznie musi też udawać switcha dla stringów. Rzecz w tym, aby każdy if miał podobną formę – na tyle podobną, że aż prosi się o jej zmakrowanie:

  1. #define C(val,code) else if (s == #val) { code; }

To by wyszło gdyby nie feler w postaci pierwszego ifa, który bynajmniej nie zaczyna się wcale od else‘a. Można jednak sprawdzić, żeby tak było. Jak?… Ano właśnie dzięki zawsze fałszywemu if(false):

  1. if (false) { }
  2. else if (s == "foo") DoSomething1(z);
  3. // ...

Robi on dokładnie nic, ale jednocześnie sprawia, że następujące dalej, prawdziwe ify mają dokładnie taką samą strukturę. Teraz już możemy je skrócić:

  1. #define C(val,code) else if (s==#val) {code;}
  2. if (false) { } C(foo,DoSth1(z)) C(bar,DoSth2(x,y)) C(baz,DoSth3())
  3. #undef C

Naturalnie dla trzech wariantów taka zabawa nie ma specjalnego sensu, ale dla dłuższej listy – czemu nie? Sam użyłem tej sztuczki parę razy, m.in. w parserze wyrażeń matematycznych, gdzie ciąg ifów wybierał wywołanie jednej z ponad 20 wbudowanych w niego funkcji. Nie jest to ładne – trzeba to przyznać – ale cóż, takie jest życie: czasami rozwiązania eleganckiego po prostu nie ma…

Tags: , ,
Author: Xion, posted under Programming »


3 comments for post “if (false) { }”.
  1. michał b.:
    May 23rd, 2010 o 18:38

    #define C(val,arg) else if (s==#arg) {code;}

    a gdzie tu jest ‘code’?

  2. Xion:
    May 23rd, 2010 o 19:58

    Ups! Pomiąchały mi się coś te argumenty makr. Ale już poprawiłem :) Dzięki.

  3. moriturius:
    May 26th, 2010 o 22:58

    Ciekawe. Nie sadzilem ze taka instrukcje mozna jakos wykorzystac :)

    Jedno o czym warto wspomniec to zeby koniecznie pisac takie makro zaraz nad kawalkiem kodu ktory z niego korzysta – tak jak zrobiles tutaj.
    Pisanie tego w osobnym miejscu mogloby zaskutkowac co najmniej nie zrozumieniem kodu przez czytajacego ;)

Comments are disabled.
 


© 2018 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.