Załóżmy, że chcę napisać funkcję, która łączy dwa ciągi znaków w C. Sposób, w jaki napisałbym to:
void concat(char s[], char t[]){
int i = 0;
int j = 0;
while (s[i] != '\0'){
i++;
}
while (t[j] != '\0'){
s[i] = t[j];
i++;
j++;
}
s[i] = '\0';
}
Jednak K&R w swojej książce zaimplementował to inaczej, szczególnie włączając w to możliwie jak najwięcej części warunkowej pętli while:
void concat(char s[], char t[]){
int i, j;
i = j = 0;
while (s[i] != '\0') i++;
while ((s[i++]=t[j++]) != '\0');
}
Który sposób jest preferowany? Czy zachęca się lub zniechęca do pisania kodu tak, jak robi to K&R? Wierzę, że moja wersja byłaby łatwiejsza do odczytania przez innych ludzi.
programming-practices
coding-style
Richard Smith
źródło
źródło
while (*s++ = *t++);
(Moje C jest bardzo zardzewiałe, czy potrzebuję tam parens, aby operator miał pierwszeństwo?) Czy K&R wydało nową wersję swojej książki? Ich oryginalna książka miała wyjątkowo zwięzły i idiomatyczny kod.'\0'
zt
(nawhile
wyjściach pierwszy). Spowoduje to pozostawienie powstałegos
ciągu bez zakończenia'\0'
(chyba że lokalizacja pamięci została już wyzerowana). Drugi blok kodu utworzy kopię zakończenia'\0'
przed wyjściem zwhile
pętli.Odpowiedzi:
Zawsze wolę jasność niż spryt. W przeszłości najlepszym programistą był ten, którego kodu nikt nie mógł zrozumieć. „Nie rozumiem jego kodu, musi być geniuszem” - powiedzieli. Obecnie najlepszym programistą jest ten, którego kod każdy może zrozumieć. Czas na komputerze jest teraz tańszy niż czas programisty.
Bez wątpienia wybrałbym opcję A. I to jest moja ostateczna odpowiedź.
źródło
if (a=b)
można go łatwo pomylićif (a==b)
.while ((c = fgetc(file)) != EOF)
jako pierwszy, jaki przychodzi mi do głowy.Złota zasada, podobnie jak w odpowiedzi Tulainsa Córdovej, polega na pisaniu zrozumiałego kodu. Ale nie zgadzam się z wnioskiem. Ta złota zasada oznacza pisanie kodu, który zrozumie typowy programista, który skończy utrzymywanie kodu. I jesteś najlepszym sędzią, kto jest typowym programistą, który skończy utrzymywać twój kod.
Dla programistów, którzy nie zaczynali od C, pierwsza wersja jest prawdopodobnie łatwiejsza do zrozumienia, z powodów, które już znasz.
Dla tych, którzy dorastali w tym stylu C, druga wersja może być łatwiejsza do zrozumienia: dla nich równie zrozumiałe jest to, co robi kod, dla nich pozostawia mniej pytań, dlaczego jest napisane tak, jak jest, i dla nich , mniej miejsca w pionie oznacza, że na ekranie można wyświetlić więcej kontekstu.
Musisz polegać na własnym rozsądku. Dla kogo chcesz ułatwić zrozumienie kodu? Czy ten kod jest napisany dla firmy? Zatem docelowymi odbiorcami są prawdopodobnie inni programiści w tej firmie. Czy to osobisty projekt hobby, nad którym nikt nie będzie pracował, tylko Ty? Jesteś więc własną grupą docelową. Czy ten kod chcesz udostępnić innym? Ci inni to twoi odbiorcy docelowi. Wybierz wersję pasującą do tej grupy odbiorców. Niestety nie ma jednego preferowanego sposobu zachęcania.
źródło
EDYCJA: Linia
s[i] = '\0';
została dodana do pierwszej wersji, tym samym naprawiając ją zgodnie z opisem w wariancie 1 poniżej, więc nie dotyczy to już bieżącej wersji kodu pytania.Druga wersja ma tę wyraźną zaletę, że jest poprawna , podczas gdy pierwsza nie jest - nie kończy poprawnie łańcucha docelowego.
„Przypisanie w stanie” pozwala bardzo zwięźle wyrazić koncepcję „kopiuj każdy znak przed sprawdzeniem znaku zerowego” oraz w sposób, który sprawia, że optymalizacja kompilatora jest nieco łatwiejsza, chociaż wielu inżynierów oprogramowania uważa, że ten styl kodu jest mniej czytelny . Jeśli nalegasz na użycie pierwszej wersji, będziesz musiał albo
źródło
Odpowiedzi Tulainsa Córdova i hvd dość dobrze obejmują aspekty przejrzystości / czytelności. Pozwól mi rzucić okiem jako kolejny powód na korzyść zadań w warunkach. Zmienna zadeklarowana w warunku jest dostępna tylko w zakresie tej instrukcji. Nie możesz później użyć tej zmiennej przypadkowo. Do pętli robi to od wieków. I jest to na tyle ważne, że nadchodzące C ++ 17 wprowadzi podobną składnię dla if i switch :
źródło
Nie. Jest to bardzo standardowy i normalny styl C. Twój przykład jest zły, ponieważ powinien być po prostu pętlą for, ale ogólnie nie ma w tym nic złego
na przykład (lub z chwilą).
źródło
!= NULL
.(x != NULL) != 0
. Po tym wszystkim, to co C jest naprawdę sprawdzenie, prawda?W czasach K&R
while ((s[i++]=t[j++]) != '\0')
odwzorowuje jedną instrukcję na większości procesorów (oczekuję Dec VAC)Tam dni
(Uwaga na temat zawsze używania nawiasów klamrowych - pierwszy zestaw kodu zajmuje więcej miejsca z powodu „niepotrzebnych”
{}
, z mojego doświadczenia często uniemożliwiają kod, który został źle scalony z kompilatora i pozwalają na błędy z nieprawidłowymi miejscami docelowymi „;” wykryte przez narzędzia.)Jednak w dawnych czasach druga wersja kodu byłaby przeczytana. (Jeśli mam rację!)
źródło
Nawet bycie w stanie to zrobić, to bardzo zły pomysł. Nazywa się to potocznie „The Last Last Bug”:
Chociaż prawdopodobnie nie popełniasz tak poważnego błędu, bardzo łatwo jest przypadkowo zepsuć się i spowodować trudny do znalezienia błąd w bazie kodu. Większość nowoczesnych kompilatorów wstawi ostrzeżenie o zadaniach wewnątrz warunku. Są tam z jakiegoś powodu, a ty dobrze byś je posłuchał i po prostu uniknął tego konstruktu.
źródło
CODE_RED = alert
aby dać błąd kompilatora.Oba style są dobrze uformowane, poprawne i odpowiednie. To, który jest bardziej odpowiedni, zależy w dużej mierze od wytycznych stylu Twojej firmy. Nowoczesne środowiska IDE ułatwią korzystanie z obu stylów poprzez użycie podszewek składni na żywo, które wyraźnie podkreślają obszary, które mogłyby stać się źródłem pomieszania.
Na przykład Netbeans wyróżnia następujące wyrażenie :
na podstawie „przypadkowego przeniesienia”.
Aby wyraźnie powiedzieć Netbeansowi, że „tak, naprawdę chciałem to zrobić ...”, wyrażenie można zawrzeć w nawiasie.
Ostatecznie wszystko sprowadza się do wytycznych dotyczących stylu firmy i dostępności nowoczesnych narzędzi ułatwiających proces rozwoju.
źródło