## Oparte na NetBSD source code style => https://cvsweb.netbsd.org/bsdweb.cgi/src/share/misc/style?rev=HEAD&content-type=text/x-cvsweb-markup ``` /* * Bardzo ważne jednoliniowe komentarze wyglądają tak. */ /* Większość jednoliniowych komentarzy wygląda tak */ /* * Wieloliniowe komentarze wyglądają tak. Układaj normalne zdania. * Wypełnij je żeby wyglądały jak prawdziwe akapity. */ ``` Linia powinna mieć max 80 znaków Nagłówek powinien sam się chronić przed wielokrotnym dołączaniem. ``` #ifndef __PLIK_H #define __PLIK_H ... #endif /* __PLIK_H */ ``` Dołączaj nagłówki do nagłówka tylko jeśli potrzeba, głównie dla definicji typów i makr używanych w tym pliku. Unikaj przechodnich dołączeń. Unikaj dołączeń dla typów struktur lub unii używanych tylko we wskaźnikach - nie wymagają definicji typu. Zamiast tego użyj wstępnej deklaracji ze słowem kluczowym struct lub union. ``` struct dirent; ``` Zdefiniuj publiczne struktury lub unie tylko jeśli są dostępne dla użytkowników. W przeciwnym razie trzymaj je prywatnie w plikac .c lub "_impl.h" lub "_private.h". Nie twórz typedef jak "typedef struct example example_t;" czy "typedef struct example *example_t;". Użyj "struct example" lub "struct example *" w publicznym API, żeby nie wymagać dołączeń. ``` struct example { struct data *p; int x; char y; }; ``` Używaj typedef z głową. Funkcje lub wskaźniki do funkcji ``` typedef void sighandler_t(int); ``` Jeśli używasz wskaźnika do struktury jako argumentu lub wartości zwracanej, bez zaglądania do środka, nie używaj typedef, użyj "struct foo *" bez publicznej definicji foo, dzięki czemu kompilator może wykryć błędy typów, a inne pliki nagłówkowe mogą użyć "struct foo *" bez dodatkowych zależności. Deklaracje "extern" mogą być użyte tylko w plikach nagłówkowych, anie w plikach .c - dzięki czemu ten sam plik używa deklaracji i definicji, dając szansę kompilatorowi do znalezienia błędów. Deklaracje funkcji extern nie powinny używać słowa kluczowego extern, nie jest to wymagane. Wyjątek instrukcja napisana w asemblerze w pliku o takiej samej nazwie z .S Na górze pliku .c funkcje statyczne. ``` static char *function(int, int, float, int); static int dirinfo(const char *, struct stat *, struct dirent *, struct statfs *, int *, char **[]); static void usage(void) __dead; /* declare functions that don't return dead */ ``` Enumy z dużymi literami, bez przecinka na końcu. ``` enum enumtype { ONE, TWO }; ``` Zmienne w strukturze zoptymalizowane pod kątem użycia pamięci, potem po rozmiarze, potem alfabetycznie. Np. zamiast: ``` int a; char *b; int c; char *d ``` użyj: ``` int a; int b; char *c; char *d ``` Każda zmienna w osobnej linii. Główne struktury na górze pliku .c lub .h jeśli użyte gdzie indziej Użycie struktury osobno od deklaracji, extern jeśli definicja w .h Nie używaj typedef dla struktur i unii, inne nagłówki mogą użyć wskaźnika do nich bez wciągania nagłówka z typedef. ``` struct foo { struct foo *next; /* List of active foo */ struct mumble amumble; /* Comment for mumble */ int bar; unsigned int baz:1, /* Bitfield; line up entries if desired */ fuz:5, zap:2; uint8_t flag; }; struct foo *foohead; /* Head of global foo list */ ``` Komentarze przed funkcjami oraz main - co robi program. getopt do parsowania parametrów programu. switch - spadające case bez break poinny mieć komentarz FALLTHROUGH Walidować poprawność typów numerycznych. Nieosiągalny kod oznaczyć komentarzem NOTREACHED. Spacje po słowach kluczowych (while, for, return, switch). Typ zwracany funkcji w osobnej linii ``` static char * function(int a1, int a2, float fl, int a4) ``` Deklaracji zmiennych w funkcji - można dać kilka zmiennych w linii, jeśli linia zbyt długa powtórz typ w następnej. Prototyp funkcji i deklaracje zewnętrznych danych powinny być w .h Unikaj inicjalizacji w deklaracji. Przesuń deklaracje bliżej użycia i inicjalizuj kiedy trzeba. Rzutowanie i sizeof nie mają spacji za sobą. Nawiasy zawsze przy sizeof. Brak nawiasów za return. NULL jest dowolnego typu wskaźnikowego, i nie wymaga rzutowania. Użyj NULL zamiast (struct foo *)0 czy (struct foo *)NULL. Testuj na null żeby wskazać typ: ``` (p = f()) == NULL ``` a nie: ``` !(p = f()) ``` Wyjątek funkcje wariadyczne: rzutuj null na (void *) bo na niektórych maszynach sizeof(pointer) != sizeof(int) ! - tylko do boolean. Np. "if (*p == '\0')", a nie "if (!*p)". Funkcje zwracające void * nie powinny go rzutować na nic. Preferuj sizeof(*var) zamiast sizeof(type), bo zmiana typu wymaga tylko jednej edycji. Sprawdzaj sysscalls na -1 zamiast < 0 ``` if (stat(p, sb) == -1) err(EXIT_FAILURE, "Unable to stat %s", p); ``` Żeby wypisać zmienne większe od long, rzutuj je na intmax_t lub uintmax_t i użyj %j ``` (void)printf("The size of %s is %jd (%#ju)\n", p, (intmax_t)sb->st_size, (uintmax_t)sb->st_size); ``` ## Oparte na Style guide for FreeBSD => https://man.freebsd.org/cgi/man.cgi?query=style&sektion=9 * grepowane linie: diagnostyka, błąd nie powinny być łamane Nagłówek z prawammi autorskimi powinien być wieloliniowym komentarzem, w pierwszej linii z myślnikiem jako znakiem po gwiazdce: ``` /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 1984-2025 John Q. Public * * Long, boring license goes here, but trimmed for brevity */ ``` Następnie pusta linia przed globalnymi plikami nagłówkowymi. Posortowane alfabetycznie: ``` #include #include ``` Kolejna pusta linia przed lokalnymi #include'ami. ``` #include "pathnames.h" ``` Nie #define'uj ani nie deklaruj nazw w przestrzeni implementacji, z wyjątkiem interfejsów aplikacji. Makra z efektami ubocznymi i definicjami stałych, są pisane dużymi literami. Jeśli są wieloliniowe wyrównaj backslashe następnej linii Obejmij je do-while żeby można ich używać w warunku if. ``` #define MACRO(x, y) do { \ variable = (x) + (y); \ (y) += 2; \ } while (0) ``` Używaj albo spacji albo tabów. Wybierz raz i się tego trzymaj. ``` #ifdef KTRACE #include #endif ``` Koniec dużych #ifdef'ów możesz skomentować: ``` #ifdef COMPAT_43 /* Dużo linii kodu. */ #else /* !COMPAT_43 */ /* I tutaj też. */ #endif /* COMPAT_43 */ #ifndef COMPAT_43 /* Dużo linii kodu. */ #else /* COMPAT_43 */ /* I tutaj też. */ #endif /* !COMPAT_43 */ ``` Używaj typów bez znaku "ISO C99" w formie uintXX_t Używaj typu ISO C99 bool zamiast int czy boolean_t. Inkluduj Preferowane nazwy_podkreslenia zamiast camelCase czy TitleCase. Zmienne w strukturze: deklaruj posortowane po użyciu, potem po rozmiarze od największego, potem alfabetycznie. Każda ma osobną linię. Oddziel typ od nazwy tabulacjami, tak żeby były wyrównane do kolejnych linii. Nazwy po bardzo długim typie powinny być oddzielone pustą linią. Główne struktury powinny być zdeklarowane na górze pliku, w którym są używane, lub w oddzielnym pliku nagłówkowym jeśli są używane w wielu plikach. Użycie struktury powinno być oddzielne od deklaracji, i extern'owe jeśli zdeklarowane w pliku nagłówkowym. ``` struct foo { struct foo *next; /* Lista aktywnych foo. */ struct mumble amumble; /* Komentarz dla mumble. */ int bar; /* Staraj się wyrównać komentarze */ struct verylongtypename *baz; /* Nie mieści się w dwóch tab */ }; struct foo *foohead; /* Głowa globalnej listy foo. Osobno od deklaracji */ ``` Używaj makr FreeBSD queque zamiast bawić się we własne listy. ``` #include struct foo { LIST_ENTRY(foo) link; /* Use queue macros for foo */ struct mumble amumble; /* Comment for mumble. */ int bar; /* Try to align the comments. */ struct verylongtypename *baz; /* Does not fit in 2 tabs. */ }; LIST_HEAD(, foo) foohead; /* Head of global foo list. */ ``` Unikaj typedef dla struktur. Wszystkie funkcje powinny mieć gdzieś zdeklarowane prototypy. Prywatne funkcje(używane tylko w jednym pliku) powinny być na górze pierwszego pliku źródłowego. Te funkcje lokalne powinny mieć deklarację static. Funkcje używane gdzieś indziej powinny być zdeklarowane w pliku nagłówkowym. Posortuj je logicznie, preferuj alfabetycznie. Wyrównuj nazwy funkcji. ``` static char *function(int _arg, const char *_arg2, struct foo *_arg3, struct bar *_arg4); static void usage(void); /* * Komentuj co robią główne funkcje. Funkcja main powinna mówić co robi program. */ ``` Używaj getopt(3) do parsowania argumentów. Użycie argumentów posortowane alfabetycznie. Użyj komentarza /* FALLTHROUGH */ jeśli case spada do następnego case'a. Sprawdzaj poprawność argumentów numerycznych. Niedostępny kod skomentuj /* NOTREACHED */. ``` while ((ch = getopt(argc, argv, "abNn:")) != -1) switch (ch) { /* Indent the switch. */ case 'a': /* Do not indent the case. */ aflag = 1; /* Indent case body one tab. */ /* FALLTHROUGH */ case 'b': bflag = 1; break; case 'N': Nflag = 1; break; case 'n': num = strtol(optarg, &ep, 10); if (num <= 0 || *ep != '\0') { warnx("illegal number, -n argument -- %s", optarg); usage(); } break; case '?': default: usage(); } argc -= optind; argv += optind; ``` Jedna spacja po słowach kluczowych(if, while, for, return, switch). Nawiasy dla jednolinijkowych wyrażeń albo wszędzie, albo tylko tam gdzie potrzeba przejrzystości. Użycie w funkcji powinno być jedno i to samo. Pętle bez warunku stopu powinny być for(;;) a nie while(1). Niektóre części pętli for można opuścić. ``` for (; cnt < 15; cnt++) { stmt1; stmt2; } ``` Pętla może deklarować i inicjalizować swój licznik. ``` for (int i = 0; i < 15; i++) { stmt1; } ``` Wcięcia mają 8 znaków spacji(albo tab 8 znakowy). Drugi poziom wcięcia ma 4 znaki. Długim wyrażeniom daj operator na końcu linii. ``` while (cnt < 20 && this_variable_name_is_too_long && ep != NULL) z = a + really + long + statement + that + needs + two + lines + gets + indented + four + spaces + on + the + second + and + subsequent + lines; ``` Nie dodawaj białych znaków na końcu linii, używaj spacji po tabach. Nie używaj więcej spacji niż gdyby tab dodał, nie używaj spacji przed tabem. Zamykający i otwierający nawias wąsaty jest w tej samej linii co else. Można pominąć niepotrzebne nawiasy. ``` if (test) stmt; else if (bar) { stmt; stmt; } else stmt; ``` Brak spacji po nazwie funkcji. Przecinki mają po sobie spacj. Brak spacji po '(' lub '[' i brak spacji przed ')' i ']'. ``` error = function(a1, a2); if (error != 0) exit(error); ``` Operatory jednoargumentowe nie potrzebują spacji, dwuargumentowe już tak. Używaj nawiasów tylko jeśli wymaga tego priorytet operatorów lub jeśli wyrażenie jest zagmatwane. Pamiętaj że inni mogą łatwiej się pogubić niż ty. Czy TY rozumiesz następujące? ``` a = b->c[0] + ~d == (e || f) || g && h ? i : j >> 1; k = !(l & FLAGS); ``` Wyjście z programu powinno być 0 na sukcesie, 1 na porażce/błędzie. ``` exit(0); /* * Odpuść oczywisty komentarz: * "Wyjdź z 0 na sukcesie." */ ``` Typ zwracany funkcji powinien być w osobnej linii. Nawias otwierający też. ``` static char * function(int a1, int a2, float fl, int a4, struct bar *bar) { ``` Deklaracje zmiennych sortuj po rozmiarze, potem alfabetycznie. Wiele zmiennych w linii jest ok. Jeśli linia jest zbyt długa, użyj ponownie typu w następnej. Zmienne mogą być deklarowane i inicjalizowane, zwłaszcza stałe w zakresie. Deklaracje mogą być w dowolnym bloku, ale muszą być zawsze przed wyrażeniami. Unikaj inicjalizowania skomplikowanymi funkcjami w deklaracjach. ``` struct foo one, *two; struct baz *three = bar_get_baz(bar); double four; int *five, six; char *seven, eight, nine, ten, eleven, twelve; four = my_complicated_function(a1, f1, a4); ``` Nie deklaruj funkcji w bloku funkcji. ANSI C mówi, że są widoczne w zakresie pliku, a nie bloku. Rzutowanie i sizeof nie mają po sobie spacji. sizeof zawsze ma pojedyncze nawiasy. NULL jest preferowaną stałą pustego wskaźnika. Nie używaj (type*)0 czy (type *)NULL gdzie kompilator zna typ, np: w przypisaniach. Testuj wskaźniki na NULL'a ``` (p = f()) == NULL ``` a nie: ``` !(p = f()) ``` Używaj ! tylko do typu bool, np. użyj: ``` if (*p == '\0') ``` a nie: ``` if (!*p) ``` Procedury zwracające void * nie powinny go rzutować na żaden typ wskaźnika. Wartości w wyrażeniach zwracanych powinny być objęte w nawiasy. Nie używaj deklaracji i definicji w stylu K&R, są stare i zabronione w C23. Długa lista parametrów powinna być wcięta na cztery spacje. Zmienna lista argumentów powinna wyglądać tak: ``` #include void vaf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); STUFF; va_end(ap); /* No return needed for void functions. */ } static void usage(void) { /* Opcjonalna pusta linia. */ ``` Opcjonalnie daj pustą linię na początku funkcji bez lokalnych zmiennych. Nie wstawiaj pustej jeśli funkcja ma zmienne, daj pustą po deklaracjach, a przed pierwszym wyrażeniem. Używaj printf zamiast fputs, puts, putchar. Pomoc użycia(usage) programu powinien być w tej kolejności 1. Opcje bez operandów alfabetycznie w pojedynczych kwadratowych nawiasach ('[' i ']'). 2. Następnie opcje z operandami alfabetycznie, każda opcja i jej argumenty we własnej parze nawiasów. 3. Wymagane argumenty (jeśli są) następne, w kolejności wymaganej w użyciu. 4. W końcu opcjonalne, wszystkie w nawiasach. Kreska pionowa '|' oddziela opcje "albo-albo" i opcje "lub", wewnątrz nawiasów. ``` "usage: f [-aDde] [-b b_arg] [-m m_arg] req1 req2 [opt1 [opt2]]\n" "usage: f [-a | -b] [-c [-dEe] [-n number]]\n" (void)fprintf(stderr, "usage: f [-ab]\n"); exit(1); ``` W manualu powinny być alfabetycznie. Używaj opcji kompilatora -Wall i staraj się unikać ostrzeżeń. ## Linux kernel coding style (pobieżnie) => https://www.kernel.org/doc/html/v6.13-rc1/process/coding-style.html 8 znaków wcięcia, 16 drugiego poziomu, itp - jeśli masz 4+ poziomy wcięcia to robisz coś źle. Switch i case w tym samym wcięciu: ``` switch (suffix) { case 'G': case 'g': mem <<= 30; break; case 'M': case 'm': mem <<= 20; break; case 'K': case 'k': mem <<= 10; fallthrough; default: break; } ``` Każde wyrażenie w osobnej linii, nie rób: ``` if (condition) do_this; do_something_everytime; ``` Nie używaj przecinka ',' zamiast nawiasów: ``` if (condition) do_this(), do_that(); ``` Zawsze używaj nawiasów dla wielu wyrażeń: ``` if (condition) { do_this(); do_that(); } ``` Nie rób wielokrotnych przypisań w linii: ``` a = b = 5; ``` Jak K&R przykazali nawias { jest na końcu linii, a } w nowej: ``` if (x is true) { we do y } ``` Wyjątek funkcje: ``` int function(int x) { body of function } ``` Wyjątek do-while: ``` do { body of do-loop } while (condition); ``` Wyjątek: ``` if (x == y) { .. } else if (x > y) { ... } else { .... } ``` Nie używaj nawiasów dla jednego wyrażenia: ``` if (condition) action(); ``` oraz ``` if (condition) do_this(); else do_that(); ``` Używaj nawiasów dla kilku wyrażeń w pętli: ``` while (condition) { if (test) do_something(); } ``` Zakaz: ‘master / slave’ => ‘{primary,main} / {secondary}’ ‘blacklist / whitelist’ => ‘denylist / allowlist’ ‘blocklist / passlist’ Odpuść sobie typedef. Funkcje robią jedną rzecz. Mieszczą się w terminalu 80x24. Rozbij większe na inline pomocnicze funkcje. Max 5-10 zmiennych użytych. Używaj goto z ładnymi labelkami. Nie jesteś na uniwersytecie, kto Ci zabroni. ## Google C++ Style Guide (tylko to co dotyczy C) W plikach nagłówkowych używaj guard'ów, plik.h: Jak używasz czegoś w pliku źródłowym to include'uj nagłówek. Nie polegaj na reakcji łańcuchowej, że nagłówek include'uje ci nagłówki Unikaj prototypów bez definicji w plikach źródłowych: ```c // In a C++ source file: class B; void FuncInB(); extern int variable_in_b; ABSL_DECLARE_FLAG(flag_in_b); ``` Używaj plików nagłówkowych. ```c // b.h: struct B {}; struct D : B {}; // good_user.cc: #include "b.h" void f(B*); void f(void*); void test(D* x) { f(x); } // Calls f(B*) ``` Unikaj inline, chyba że 10 lub mniej linijek. Nazwy plików: małe znaki i podkreślnik: * my_useful_class.cc * myusefulclass.cc * myusefulclass_test.cc Jeśli używasz #include do ładowania nie plików nagłówkowych (czemu to robisz?), to użyj rozszerzenia .inc zamiast .h