Komentarz to tekst, który kompilator wyrzuca. Istnieje wyłącznie dla ludzi, którzy będą później czytać kod, a jednym z nich zwykle jesteś ty. C oferuje dwie formy, a zrozumienie, kiedy która jest właściwym narzędziem, zajmuje jakieś dwie minuty.
Dwie formy
Uruchom to: wynik ma jedną linię. Oba komentarze zostały usunięte, zanim kompilator w ogóle przeanalizował program; nic nie kosztują w czasie działania i nic nie dodają do pliku wykonywalnego.
// trwa do końca fizycznej linii. Nic nie może stać za nim w tej linii, więc to nie działa tak, jak wygląda:
int x = 5; // ustaw x na pięć int y = 6; /* y nigdy nie zostaje zadeklarowane */
/* ... */ kończy się na pierwszym */, gdziekolwiek ono jest. Może zaczynać się i kończyć w środku linii, co czasem się przydaje:
int total = price /* przed podatkiem */ + shipping;
Dlaczego istnieją dwa style
/* */ to oryginalne C z 1972 roku. // przyszło z C++ i zostało oficjalnie dodane do C dopiero w C99. Ta historia wyjaśnia coś, co zauważysz, czytając starszy kod: biblioteki pisane z myślą o przenośności do C89 używają /* */ nawet dla komentarzy jednoliniowych, bo // nie skompilowałoby się na starych narzędziach, które wciąż wspierały.
Dziś każdy kompilator, którego raczej użyjesz, akceptuje oba. Używaj // do zwykłych uwag, a /* */, gdy komentarz naprawdę zajmuje kilka linii. Jeśli celujesz w bardzo stary kompilator dla systemów wbudowanych, sprawdź to, zanim zaczniesz polegać na //.
Komentarzy nie da się zagnieżdżać
To jedyna prawdziwa pułapka:
/* Na razie wyłącz tę sekcję
int a = compute();
/* klasyczna funkcja pomocnicza: miej ją na oku */
int b = a * 2;
*/
Komentarz blokowy kończy się na pierwszym */, czyli tym w linii 3. Linie 4 i 5 są wtedy znowu żywym kodem, a końcowe */ w linii 6 to błąd składni. Komunikat kompilatora wskazuje ostatnią linię i nic nie mówi o przyczynie.
Rozwiązaniem jest użycie preprocesora, który radzi sobie z zagnieżdżaniem:
#if 0
int a = compute();
/* klasyczna funkcja pomocnicza: miej ją na oku */
int b = a * 2;
#endif
#if 0 nigdy nie jest prawdą, więc preprocesor usuwa wszystko aż do #endif, zanim kompilator to zobaczy. Radzi sobie z komentarzami, cudzysłowami i innymi blokami #if w środku, a przy sprzątaniu łatwo go wyszukać.
Zakomentowywanie kodu podczas debugowania
Tymczasowe usunięcie linii to najczęstsze codzienne zastosowanie komentarzy. Gdy program zachowuje się dziwnie, wyłączanie po jednej instrukcji pokazuje, która z nich ma znaczenie.
Odkomentuj printf i uruchom ponownie, żeby zobaczyć, jak pętla buduje wynik. Śledzenie wypisywaniem nie jest eleganckie, ale w C jest szybkie i zawsze działa: debugger powie ci więcej, a printf powie ci coś od razu.
Dwa nawyki chronią przed bałaganem. Usuwaj zakomentowany kod, zanim zrobisz commit; system kontroli wersji pamięta starą wersję, więc ty nie musisz. A gdy celowo zostawiasz wyłączoną linię, napisz obok, dlaczego.
Komentarze dokumentacyjne
Komentarz blokowy nad funkcją to miejsce, w którym wyjaśniasz, co ona robi, co znaczą jej parametry i co w niej zaskakującego.
Narzędzia takie jak Doxygen czytają takie ustrukturyzowane komentarze i generują z nich dokumentację referencyjną. Własny styl Doxygena używa /** ... */ ze znacznikami @param i @return:
/**
* Zamienia stopnie Celsjusza na stopnie Fahrenheita.
* @param c temperatura w stopniach Celsjusza
* @return ta sama temperatura w stopniach Fahrenheita
*/
double celsius_to_fahrenheit(double c);
Do własnego kodu nada się każdy z nich. Liczy się to, żeby komentarz był obok deklaracji, którą ludzie czytają, zwykle w pliku nagłówkowym, a nie zakopany w implementacji.
Co warto komentować
Zasada, która przetrwa zetknięcie z prawdziwym kodem: komentuj dlaczego, a nie co.
i++; // zwiększ i <- nie mówi nic, czego nie powiedział kod
/* Pomiń BOM: pliki eksportowane przez stary system zaczynają się
od trzech bajtów, które nie są częścią danych. */
offset += 3;
Drugi komentarz zawiera informację, której nie ma nigdzie w kodzie. Pierwszy to szum, który w końcu zacznie przeczyć linii, którą opisuje, bo komentarzy nikt nie aktualizuje, gdy kod się zmienia.
Rzeczy, które w C szczególnie warto skomentować:
- Kto jest właścicielem tej pamięci. Jeśli funkcja zwraca wskaźnik, który wywołujący musi zwolnić przez
free, napisz to. C nie ma jak wyrazić tego w typie. - Jednostki i zakresy.
int timeout;jest niejednoznaczne: sekundy czy milisekundy? - Nieoczywista poprawność. Dlaczego pętla kończy się na
n - 1, dlaczego to rzutowanie jest bezpieczne, dlaczego bufor ma 256 bajtów. - Celowe dziwactwa. Kod, który wygląda na błąd, ale nim nie jest, przyciąga "poprawki" przyszłych czytelników, chyba że jest opisany.
Ten komentarz zasługuje na swoje miejsce: linia pod nim wygląda na zbędną, a nie jest.
Komentarze w stringach to nie komentarze
Ostatni szczegół. Znaczniki komentarzy nie mają specjalnego znaczenia wewnątrz literału stringowego ani stałej znakowej:
Obie linie wypisują się w całości. Kompilator dzieli stringi na tokeny, zanim zacznie szukać komentarzy, więc // w cudzysłowie to po prostu dwa znaki. (%% w pierwszej linii to sposób na wypisanie dosłownego znaku procentu przez printf: samo % rozpoczyna specyfikator formatu.)
Najczęściej zadawane pytania
Jak napisać komentarz w C?
Na dwa sposoby. // to jest komentarz trwa do końca linii. /* to jest komentarz */ może obejmować dowolną liczbę linii i kończy się na zamykającym */. Oba są usuwane przed kompilacją, więc nigdy nie wpływają na program.
Czy C obsługuje komentarze //?
Tak, od C99. Zostały zapożyczone z C++ i dziś obsługuje je każdy kompilator. Odrzucają je tylko naprawdę stare kompilatory C89, dlatego bardzo stary kod używa /* */ do wszystkiego, nawet do jednej linii.
Czy w C można zagnieżdżać komentarze?
Nie. /* zewnętrzny /* wewnętrzny */ nadal zewnętrzny */ kończy się na pierwszym */, zostawiając nadal zewnętrzny */ jako zepsuty kod. Żeby wyłączyć blok, który już zawiera komentarze /* */, użyj #if 0 ... #endif, które zagnieżdża się poprawnie.
Jak zakomentować blok kodu w C?
Otocz go /* */, jeśli w środku nie ma komentarzy blokowych, albo poprzedź każdą linię //. Solidna opcja dla dużych fragmentów to #if 0 przed i #endif po: preprocesor usuwa wszystko pomiędzy i radzi sobie z komentarzami i cudzysłowami w środku.