Czy konieczne jest przestrzeganie tego standardu, czy w tym celu zastosować standard C?

17

Na Stack Overflow jest kilku bardzo doświadczonych ludzi, którzy zawsze mówią o standardzie C. Ludzie wydają się nie lubić nieprzenośnych rozwiązań, nawet jeśli dla mnie działają. Ok, rozumiem, że należy przestrzegać tego standardu, ale czy nie ogranicza to kreatywności programisty?

Jakie są konkretne korzyści płynące z przestrzegania normy? Zwłaszcza, że ​​kompilatory mogą nieco inaczej implementować standard.

0decimal0
źródło
7
Czy możesz wyjaśnić, co rozumiesz przez „standard”? Czy masz na myśli nie poleganie na zachowaniu, które nie jest zdefiniowane przez standard? A może nie używasz rozszerzeń / funkcji kompilatora? A może stylowe konwencje?
ikh
1
@ikh Zajmuje się normami ISO C (C90, C99, C11).
Aseem Bansal,
9
To tak samo, jak mówienie, że pisanie lub mówienie po angielsku, przy użyciu gramatyki i słownictwa angielskiego, kładzie kajdany na twojej kreatywności. Oczywiście ludzie mogą robić cudowne rzeczy, łamiąc zasady, kosztem spójności, ale możesz pisać miliony kreatywnych książek, zachowując przy tym „standard” angielskiego.
Avner Shahar-Kashtan
czy możesz dodać przykład „Ludzie wydają się nie lubić nieprzenośnych rozwiązań, nawet jeśli dla mnie działają”?
BЈовић
1
@PHIfounder Aby rozwiązać ten ostatni przypadek, możesz pominąć zwrot z głównego, domyślnie zwraca 0 :)
Daniel Gratzer

Odpowiedzi:

45

Istnieje kilka powodów, dla których trzymanie się standardu jest dobrą rzeczą.

  1. Zamknięcie w kompilatorze jest do bani. Jesteś całkowicie na łasce grupy programistów z ich własnym programem. Najwyraźniej nie chcą cię zdobyć ani nic, ale jeśli twój kompilator zacznie opóźniać się w optymalizacji, nowych funkcjach, poprawkach bezpieczeństwa itp., To źle; Utknąłeś. W skrajnych przypadkach niektóre firmy muszą rozpocząć łatanie dowolnego narzędzia, od którego się uzależniły. Jest to ogromna strata pieniędzy i czasu, gdy istnieją inne narzędzia robocze.

  2. Zamknięcie na platformie jest do bani mocniejsze. Jeśli naciskasz oprogramowanie na Linuksa i chcesz przejść na system Windows, ponieważ zdajesz sobie sprawę, że Twój rynek naprawdę istnieje, będziesz miał sporo czasu, zmieniając każdy nieprzenośny hack, który masz w kodzie, aby grać fajnie zarówno z GCC, jak i MSVC. Jeśli masz kilka podstawowych elementów opartych na czymś takim, powodzenia!

  3. Najtrudniejsze są do tyłu niezgodne zmiany. Standard nigdy nie złamie twojego kodu (Ignoruj ​​python). Jednak niektórzy pisarze kompilatorów losowych mogą zdecydować, że ten dodatek specyficzny dla implementacji nie jest wart zachodu i porzucić go. Jeśli zdarzy ci się na nim polegać, utkniesz na jakiejkolwiek starej, nieaktualnej wersji, w której był ostatnio.

Tak więc nadrzędny komunikat, trzymanie się standardu, czyni cię bardziej elastycznym . Masz bardziej ograniczony język, ale masz więcej

  • Biblioteki
  • Wsparcie (ludzie znają standard, nie każdy zawiły hack specyficzny dla kompilatora)
  • Dostępne platformy
  • Dojrzałe narzędzia
  • Bezpieczeństwo (zabezpieczenie na przyszłość)

To delikatna równowaga, ale całkowite ignorowanie standardu jest zdecydowanie błędem. Mam tendencję do organizowania mojego kodu C, aby polegać na abstrakcjach, które mogą być zaimplementowane w sposób nieprzenośny, ale które mogę transparentnie przenosić bez zmiany wszystkiego, co zależy od abstrakcji.

Daniel Gratzer
źródło
+1 w porządku :), dziękuję ... Byłem poważnie zdezorientowany sposobem, w jaki kompilatory nieco odbiegały od standardów i sprawiłem, że sceptycznie podchodziłem do ścisłego ich przestrzegania, potrzebowałem znać zalety i wady tego, a ty wyraźnie je zidentyfikowałeś.
0decimal0
6
Nieokreślone zachowanie prawdopodobnie również jest do bani. Z c łatwo jest wejść do UB, jeśli nie przestrzegasz ściśle tego standardu.
CodesInChaos
@CodesInChaos Zgoda, niezdefiniowane zachowanie jest wielki, z jednej strony, ponieważ pozwala ona na kilka szalonych optymalizacje, ale z drugiej debugowania nim ...
Daniel wiązań Simona
6

Standard jest rodzajem „kontraktu” między tobą a twoim kompilatorem, który określa znaczenie twoich programów. Jako programiści często mamy pewien mentalny model działania języka, a ten model mentalny często jest niezgodny ze standardem. (Na przykład programiści C często myślą o wskaźniku jako z grubsza „liczbie całkowitej oznaczającej adres pamięci” i dlatego zakładają, że można bezpiecznie wykonywać dowolne operacje arytmetyczne / konwersje / manipulacje na wskaźnikach, które można wykonać za pomocą liczb całkowitych oznaczających pamięć adres. To założenie nie zgadza się ze standardem; w rzeczywistości nakłada bardzo surowe ograniczenia na to, co można zrobić ze wskaźnikami).

Jaka jest zatem korzyść z przestrzegania standardu, a nie własnego modelu mentalnego?

Mówiąc najprościej, chodzi o to, że standard jest poprawny, a twój własny model mentalny jest błędny. Twój model mentalny jest zwykle uproszczonym widokiem tego, jak rzeczy działają w twoim systemie, w typowych przypadkach, z wyłączonymi wszystkimi optymalizacjami kompilatora; dostawcy kompilatorów zazwyczaj nie starają się go dostosować, szczególnie jeśli chodzi o optymalizacje. (Jeśli nie wytrzymasz końca kontraktu, nie możesz oczekiwać od kompilatora żadnego konkretnego zachowania: wyrzucanie śmieci, wyrzucanie śmieci).

Ludzie wydają się nie lubić nieprzenośnych rozwiązań, nawet jeśli dla mnie działają.

Lepiej byłoby powiedzieć „nawet jeśli wydają się dla mnie pracować”. O ile twój kompilator nie udokumentuje, że dane zachowanie będzie działać (to znaczy: chyba że używasz wzbogaconego standardu, składającego się ze standardowej właściwej dokumentacji kompilatora plus), nie wiesz, że to naprawdę działa lub że jest naprawdę niezawodne. Na przykład, przepełnienie liczb całkowitych ze znakiem zwykle powoduje zawijanie na wielu systemach (tak INT_MAX+1jest zazwyczaj INT_MIN) - z tym wyjątkiem, że kompilatory „wiedzą”, że podpisana arytmetyka liczb całkowitych nigdy nie przepełnia się w (poprawnym) programie C, i często wykonują bardzo zaskakujące optymalizacje na podstawie tego „ wiedza, umiejętności".

ruakh
źródło
1
Możesz się skompilować -fwrapv, a wtedy używasz nieco innego, niestandardowego języka, w którym arytmetyka liczb całkowitych zawsze się otacza.
user253751
@immibis: Kiedy C89 został napisany, zgodnie z jego uzasadnieniem, większość współczesnych kompilatorów zdefiniowała semantykę cichego zawijania dla przepełnienia liczb całkowitych. W wielu przypadkach posiadanie pewnego rodzaju gwarancji dotyczących tego, co dzieje się w przypadku przepełnienia liczb całkowitych, może pozwolić na większą wydajność kodu niż byłoby to możliwe bez takich gwarancji, zwłaszcza jeśli gwarancje nie posuną się tak daleko, aby wymagać dokładnego zachowania zawijania [precyzyjne zachowanie zawijania może być emulowane przy użyciu matematyki bez znaku, ale semantyka, która jest luźniejsza, ale nadal wystarczająca do spełnienia wymagań, może pozwolić na bardziej wydajny kod].
supercat 21.04.16
@immibis: Szkoda, że ​​rewizjoniści byli w stanie przekonać ludzi, że zachowania, które zostały wdrożone niemal jednogłośnie wśród kompilatorów dla niektórych platform (lub w niektórych przypadkach w 100% jednogłośnie) nigdy nie były „standardowe” na takich platformach, ponieważ w wielu przypadkach utrata wydajności wynikająca z konieczności unikania takich zachowań nie zostanie naprawiona przez „optymalizacje”, które kompilator byłby w stanie osiągnąć, odwołując je.
supercat 21.04.16
4

Rozumiem, że należy przestrzegać tego standardu, ale czy nie ogranicza on kreatywności programisty? nadal istnieją pewne różnice w sposobie, w jaki różne kompilatory przestrzegają standardów. Mogę na przykład napisać kod, który działa, bardzo dobry pod względem wydajności i szybkości, tj. Wszystko, co się liczy, ale wciąż niekoniecznie ściśle przestrzega standardów.

Nie. Standard mówi, co wolno robić. Jeśli nie jest określony, jesteś na terytorium nieokreślonego zachowania, a następnie wszystkie zakłady są wyłączone - program może nic zrobić.


Ponieważ wspomniałeś o konkretnym przykładzie void main()vs int main(), mogę poprawić moją odpowiedź.

void main()nie jest standardową deklaracją głównej funkcji. Może działać na niektórych kompilatorach poprzez rozszerzenia, ale polega na implementacji. Nawet jeśli to działa, musisz sprawdzić, czy robi to, co chcesz. Problem polega na tym, że programiści kompilatorów mogą zdecydować o usunięciu void main()w następnej wersji kompilatora, powodując uszkodzenie aplikacji.

Z drugiej strony standard wyraźnie określa podpis main as int main()i mówi, co powinien zrobić.


Z drugiej strony są rzeczy nie zdefiniowane w standardzie. Następnie może obowiązywać inny standard (na przykład POSIX). Najlepszym przykładem może być implementacja wątków w c ++ 03, ponieważ standardowe programy c ++ 03 były 1-wątkowe. W takim przypadku musisz użyć biblioteki zależnej od platformy lub czegoś w rodzaju ulepszenia .

BЈовић
źródło
4
Wszystko, co robi kompilator, co nie jest standardem, nie jest niezdefiniowanym zachowaniem, rozszerzenia kompilatora są dobrze zdefiniowane w tym sensie, że są deterministyczne i celowe. UB nie jest.
Daniel Gratzer
@ jozefg Sposób, w jaki został zapytany - oczywiste jest, że OP pomyślał o sposobie implementacji UB. Na przykład wątki nie zostały zdefiniowane w c ++ 03.
BЈовић
1
@deworde: komentarz został usunięty z odpowiedzi.
Kevin
@ jozefg Jeśli określony kompilator zawsze otacza podpisane liczby całkowite, można uznać to za nieudokumentowane rozszerzenie języka. (Oczywiście, że nieudokumentowane oznacza, że ​​nie masz gwarancji, że nie
usuną
-6

Nie postępuj zgodnie z zasadami JEŻELI twój projekt dotyczy projektów specjalnych, na przykład projektu rządowego lub wojskowego, ale musisz przestrzegać zasad JEŻELI mówisz o otwartym źródle lub dużym projekcie z rozproszonym zespołem.

Nieznany
źródło
2
bez wyjaśnienia odpowiedź ta może stać się bezużyteczna w przypadku, gdy ktoś inny wyrazi przeciwną opinię. Na przykład, jeśli ktoś opublikuje roszczenie typu „przestrzegaj reguł JEŻELI twój projekt dotyczy projektów specjalnych, na przykład projektu rządowego lub wojskowego, ale nie musisz przestrzegać reguł JEŻELI mówisz o otwartym źródle ...” , w jaki sposób ta odpowiedź pomoże czytelnikowi wybrać dwie przeciwstawne opinie? Rozważ edycję go w lepszym stanie
komnata
2
Uknown: zdziwiłbyś się, ile standardów istnieją w projektach rządowych ...
Deer Hunter