Horror nazewniczy pod Windows

Może komuś z was zdarzyło się już w programie lub bibliotece kompilowanej pod Windows (albo, co gorsza, pisanej jako przenośna i testowanej na Windows w późnej fazie rozwoju), zdefiniować np. metodę SendMessage (akurat właśnie taką mi się zdarzyło - w obiekcie obsługującym pewien mechanizm komunikacyjny). Jeśli tak, już wiecie w czym problem, jeśli nie - czytajcie dalej.

Próba kompilacji tego typu kodu generuje wyjątkowo mistyczne błędy (bardzo zależne od kontekstu więc nie będę ich tu cytował, może to np. być informacja o błędnym użyciu makra ale często jest dużo gorzej, bywa nawet, że o problemach dowiadujemy się dopiero w trakcie linkowania programu korzystającego z naszej biblioteki i to nie każdego) - w żaden sposób nie kojarzące się z kodem, który kompilujemy.

Powód jest prosty: nasza ulubiona firma Microsoft przyjęła bardzo przyjemną metodę definiowania funkcji należących do Windows API: otóż wiele z nich jest zdefiniowanych jako makra! Np. wspomniane SendMessage jest niekiedy rozwijane jako SendMessageA a niekiedy jako SendMessageW. Podobnie dzieje się z wieloma innymi funkcjami. Tak więc: dzięki twórczemu wkładowi Microsoftu założenie, że metodę mogę nazwać jak chcę, jeśli jakaś zewnętrzna funkcja nazywa się tak samo, metoda ma pierwszeństwo jest całkowicie niesłuszne.

Co gorsza, tak naprawdę nie ma na to dobrego sposobu (tego typu makr jest kilkaset, oprócz funkcji nazywanych w stylu SomeFunction dotyczy to też stałych pisanych w konwencji SOME_CONSTANT). Trzeba albo być czujnym i kompilować biblioteki na Windows przed zamrażaniem API, albo przyjąc całkowicie odmienne od stosowanych przez Microsoft standardy nazewnicze (np. send_message).

Aha: problem dotyczy dowolnego kompilatora działającego pod Windows - nie tylko Visual C++. Wszyscy, chcąc nie chcąc, wykorzystują windows.h.

komentarze obsługiwane przez Disqus