Czy dobrym nawykiem jest używanie wyrażeń C w kodzie C ++?

19

W szkole zaczęliśmy uczyć się języka C w tym roku, pomimo tego, że jestem znacznie przed klasą, a ja nauczyłem się Java, C ++ i C, podczas gdy klasa jest u podstawy C. W każdym razie, dokumentowałem siebie, czytając książki, artykuły, a ja zapytałam moją nauczycielkę, dlaczego mam się uczyć języka C, a ona powiedziała, że ​​to podstawa języka C ++. Kiedy zaczynałem programować, łatwiej było mi C ++, później nauczyłem się C. Ale w książkach widać, że kod C działa w C ++, ale nie działa odwrotnie.

Moje pytanie jest dość proste ~ Czy dobrym nawykiem jest używanie wyrażeń C w C ++? Dam ci przykład:

Powinien ten kod

#include <stdio.h>
#include <iostream>

int main() {
int x;
scanf("%d", &x);
cout << "The number you entered is " << x << "And it's double is " << x*x;
return 0;
}

Bądź bardziej wydajny lub lepszy w jakikolwiek sposób:

#include <iostream>

int main() {
int x;
cin >> x;
cout << "The number you entered is " << x << "And it's double is " << x*x;
return 0;
}

Zrobiłem już łatwą dokumentację na ten temat w niektórych zakurzonych starych książkach i z tego, co mogłem znaleźć, użycie scanf zamiast cout również opróżnia strumień lub coś takiego, więc w zasadzie pytam, czy lepiej użyć scanf i jakie konteksty

Dotyczy to również pliku IO, ponieważ zawsze uważałem, że FI IO jest łatwiejszy w C niż w C ++. To pytanie dotyczy prawie każdego ogólnego wyrażenia w C zastosowanego do C ++. Warto również zauważyć, że korzystam z nowoczesnego kompilatora, ale nie powinno to mieć znaczenia, ponieważ pytam, czy dobrym nawykiem programowania jest używanie wyrażeń C w kodzie C ++.

Prawdopodobnie są to wady i zalety, ale szukam tylko odpowiedzi typu tak / dlaczego, nie / dlaczego.

Również jeśli są jakieś szczegóły, które pominąłem, dodaj komentarz.

Bugster
źródło
12
Uważaj na miksowanie stdioi iostream. W rodzinie gwarantowana jest pewna kolejność i synchronizacja, które niekoniecznie mają zastosowanie poza nią.
David Thornley,
Dzięki za podpowiedź, ale ten fragment kodu był czystym przykładem. W każdym razie dzięki.
Bugster
25
Jeśli uczysz się programowania; Musisz nauczyć się właściwego wcięcia!
maska ​​bitowa
5
scanf () nie jest świetnym przykładem; jest tak strasznie podatny na błędy, że radzę unikać go w C lub C ++.
Russell Borogove
1
To mógł być tylko przykładowy kod, ale komentarz Dawida naprawdę trafia do sedna problemu, dlaczego powinno nie podczas programowania w C ++ używać idiomów C. Są to zupełnie inne języki; nie mylić ich bardziej niż mylić Java i C lub C ++ i Visual Basic.
Cody Gray

Odpowiedzi:

36

Nie, to zły nawyk. Gdy robisz to na co dzień, najprawdopodobniej skończysz z naruszeniem przewodników stylu, których przestrzega Twój zespół (lub przynajmniej zostaniesz pobity podczas recenzji kodu).

Tak, działa, ale jeśli istnieje odpowiednik c ++, użyj go. (np staram się nie mieszać printfsz couts)

jglouie
źródło
+1 - Krótko i na temat. To podkreśla główny punkt mojej odpowiedzi, że wytyczne zespołu pomagają zbliżać ludzi i ujednolicać ich, aby mogli współpracować.
jmort253
Ten komentarz właściwie odpowiada na moje pytanie i stanowi solidny argument. Dziękuję Ci.
Bugster
1
@ThePlan dzięki. wszyscy mieli świetne odpowiedzi na to pytanie.
jglouie
1
Uwaga: printfkonsekwentne korzystanie będzie działać tak samo, jak coutkonsekwentne. Jedyne problemy to mieszanie ich ze sobą i styl.
user253751
Czy możesz podać przykład funkcji w C, która nie ma odpowiednika C ++?
klutt
20

Ogólnie rzecz biorąc, C i C ++ są traktowane tak, jakby były dwoma całkowicie odrębnymi językami. Dlatego można uznać za złą formę użycie składni C w programie C ++.

Masz rację; jednak ten kod C będzie dobrze się kompilował. To zależy od tego, jak elastyczna jest Twoja firma pod względem przestrzegania standardów. Gdybym kiedykolwiek zadał to pytanie w wywiadzie, z pewnością poinformowałbym ankietera, że ​​C działa w C ++, ale także, że C i C ++ są dwoma oddzielnymi językami i prawdopodobnie nie powinny być mieszane, chyba że istnieje bardzo, bardzo dobry powód, aby to zrobić.

Inną rzeczą do rozważenia jest to, że standardy pomagają stworzyć platformę, na której więcej osób może z łatwością pracować z kodem. Chociaż miałeś szczęście, że masz nauczyciela, który zachęcał cię do nauki języka C, nie wszyscy mogą mieć tyle szczęścia. Dlatego mieszanie C w programie C ++ może być mylące dla kogoś, kto nigdy nie nauczył się C.

Podsumowując, sam fakt, że możesz coś zrobić, nie oznacza, że ​​powinieneś, a sam fakt, że nie możesz zrobić, nie oznacza, że ​​nie możesz :)

jmort253
źródło
Widzę. Co z funkcjonalnością, czy są jakieś szczególne przypadki, w których składnia C jest lepsza niż składnia C ++?
Bugster
10

C ++ z założenia jest wstecznie kompatybilny z C, więc zwykle kod C będzie kompilowany przez kompilator C ++ w porządku ( zwykle dlatego, że w C ++ są dodatkowe zastrzeżone słowa, które nie są w C i mogą być użyte w kodzie C przerywającym kompilację).

Uważam to jednak za złą praktykę mieszania kodu. Jeśli używasz scanf- użyj printf, jeśli używasz operator >>- użyj operator <<. Powodem jest to, że przeciążone operatory C ++ mogą zawierać funkcjonalność, o której nie wiesz, a niedopasowanie ich spowoduje, że Twój program będzie robił rzeczy, których nie chciałeś.

Nie ma szczególnego powodu, aby preferować składnię C w kodzie C ++, są to różne języki, a gdy używasz składni C w kodzie C ++ - nadal piszesz kod C ++ , po prostu nie korzystasz z wielu jego potężnych narzędzi.

littleadv
źródło
5
Niezgodność między C i C ++ to coś więcej niż tylko słowa kluczowe. System pisania zmienia się i istnieją funkcje, które istnieją w C (szczególnie C99), które nie istnieją w C ++. (Np. Tablice o zmiennej długości).
Arafangion
9

Jeśli odłożymy na bok styl kodowania i problemy estetyczne, istnieją również różne problemy techniczne, które napotykasz podczas używania C w kodzie C ++:

  • Co to jest C? C90, C99 czy C11? Mogą występować różne problemy ze zgodnością w zależności od używanego standardu C. Typ boolowski, // komentarze, funkcje C99, takie jak VLA, wyznaczone inicjatory itp.

  • C ++ ma bardziej rygorystyczne pisanie niż C. Aby skompilować kod C w C ++, najprawdopodobniej musisz dodać różne typy rzutów, aby uzyskać oczekiwany typ. Oznacza to, że może być konieczne przepisanie idealnie poprawnego kodu C o jakości produkcyjnej, aby działał w C ++.

  • Rzutowanie typowane przez ściślejsze pisanie na ogół jest po prostu dobrą rzeczą, ale w niektórych przypadkach mogą wprowadzać lub ukrywać błędy. Weźmy na przykład niesławną obsadę wyniku z malloc (). Powinno to być zapisane w C ++, ale nigdy w C. (1)

  • Mieszanie funkcjonalności C i C ++ może prowadzić do błędów i nieokreślonego zachowania. Na przykład nie będzie działało przydzielanie za pomocą malloc () i zwalnianie za pomocą delete . (2)

  • Problemy z bezpieczeństwem wątków. Biblioteka standardowa C nie jest bezpieczna dla wątków. Standardowa biblioteka C ++ może, ale nie musi być wątkowo bezpieczna, jeśli tak, to dodanie wywołań funkcji biblioteki C do kodu zniszczy to.

    Na marginesie dla programistów systemu Windows: kompilator Visual C ++ miał błąd wycieku od dłuższego czasu, gdy funkcja CreateThread () interfejsu API systemu Windows była używana w tym samym programie co biblioteka C. (3, 4)

  • Konwencja wywoływania może stanowić problem w niektórych kompilatorach, zmuszając ją extern "C"do jednoznacznego określenia, które funkcje powinny być powiązane z „konwencją wywoływania C”.

  • Irytujące szczegóły. Operator przecinka zachowuje się inaczej. Końcowy przecinek w deklaracjach struct / enum jest dozwolony w C99 / C11, ale nie w C ++. Zakres różnych rodzajów zmiennych i funkcji jest różnie traktowany. Itd itd.

Prawdopodobnie jest jeszcze więcej przypadków.


Bibliografia:

  1. http://c-faq.com/malloc/cast.html
  2. http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.3
  3. http://www.flounder.com/badprogram.htm#CreateThread
  4. http://msdn.microsoft.com/en-us/library/windows/desktop/ms682453%28v=vs.85%29.aspx

źródło
7

Powodem, dla którego C ++ może kompilować C, jest tylko „kompatybilność wsteczna” (unikaj przepisywania istniejącego działającego kodu).

Ale C ++ ma inną filozofię względem c. Pomieszanie ich nie jest dobrą usługą dla obu z nich.

Sposób, w jaki C i C ++ zarządzają we / wy, może polegać na innym sposobie zarządzania stanem wewnętrznym we / wy. Więc - przynajmniej - konsekwentnie używaj wejścia i wyjścia.

A w programach C ++ przestrzega stylu C ++ (chyba że jest to specjalnie wymagane, aby robić to gdzie indziej)

Emilio Garavaglia
źródło
5

Powiedziałbym, że najpierw nauka C jest, IMHO, dobrym pomysłem. W ten sposób ludzie zaczynają rozumieć sprzęt, dla którego piszą oprogramowanie.

Mieszanie tych dwóch języków nie jest jednak dobrym pomysłem. Ponieważ dostajesz szaloną złożoność C ++ w połączeniu z kręceniem się surowych bitów wspólnych dla C.

Jak widać, nawet w tak prostym przykładzie, jak twój, występują problemy z synchronizacją z różnymi typami strumieni i wewnętrznym buforowaniem. Ale również podejście C&C ++ nie jest w żaden sposób bardziej elastyczne. Przełącz się do klasy x, a nie ma operatorów, którzy mogliby korzystać z przesyłania strumieniowego i innych rzeczy.

To skomplikowane...

Naprawdę uważam, że dobry programista C ++ powinien wiedzieć, w jaki sposób bity są odrzucane za każdą konstrukcją i jakie są ukryte zachowania.

Ale nauka C ++, przynajmniej w ponad 50%, zajmuje ponad 5 lat profesjonalnego kodowania i po prostu nie możesz sobie z tym poradzić w programie nauczania, który trwa 6 miesięcy i 20 godzin praktycznego doświadczenia.

Gdybym używał konstruktorów C ++ w C, nie użyłbym strumieni, są one proste z lotu ptaka i sprawiają, że ludzie wierzą, że tworzenie oprogramowania jest łatwe, ale ukrywają dodatkowe złożoności bez wielu korzyści w wielu sytuacjach.

Klasy opakowujące RAII, szablony, przeciążenia, poprawność const i czyste klasy abstrakcyjne dla popularnych interfejsów (nie używaj tutaj f-ng Java PROSZĘ!) Są jednak dobrymi kandydatami. Ponieważ zwiększają bezpieczeństwo, ogólność i łatwość użytkowania, które są bardzo ważne w rzeczywistych projektach. Pamiętaj jednak o takich rzeczach, jak wirtualne zniszczenie, wybuchowa natura domyślnej budowy kopii, koszty działania, stała poprawność itp.

Koder
źródło