Strumienie C++ VS. C-style IO?
Kodowałem trochę C++ dla małego hobbystycznego projektu, kiedy zauważyłem, że używam operacji w stylu C, aby uzyskać dostęp do IO (printf
, fopen
, itd.).
Czy uważa się za" złą praktykę " Włączanie funkcji C w projekty C++? Jakie są zalety korzystania ze strumieni nad dostępem do IO w stylu C?
10 answers
To jest gorący temat.
Niektórzy ludzie wolą używać C++ IO, ponieważ są one bezpieczne dla typu (nie można mieć rozbieżności między typem obiektu a typem określonym w łańcuchu formatowania), i płyną bardziej naturalnie z resztą sposobu kodowania C++.
Istnieją jednak również argumenty przemawiające za funkcjami C IO (Moje ulubione). Niektóre z nich to:
- łatwiej integrują się z lokalizacją, ponieważ cały łańcuch do lokalizacji nie jest podzielony w mniejszych łańcuchach i przy pewnej implementacji localizer może zmienić kolejność wstawianych wartości, przenieść je w łańcuchu,...
- możesz bezpośrednio zobaczyć format tekstu, który zostanie napisany(może to być naprawdę trudne z operatorami strumienia).
- ponieważ nie ma inliningu i tylko jedna instancja funkcji
printf
, generowany kod jest mniejszy (może to być ważne w środowisku wbudowanym). - szybsza od funkcji C++ w niektórych wdrożenie.
Osobiście nie uważałbym za złą praktykę używania strumienia C w kodzie C++. niektóre organizacje zalecają nawet używanie ich nad strumieniem C++. To, co uznałbym za zły styl, to użycie obu w tym samym projekcie. Myślę, że kluczem jest tu konsekwencja.
Jak zauważyli inni, w stosunkowo dużym projekcie prawdopodobnie nie użyłbyś ich bezpośrednio, ale użyłbyś zestawu funkcji wrappera (lub klas), które najlepiej pasowałyby do twojego kodowania standard, a twoje potrzeby (lokalizacja, bezpieczeństwo typu,...). Możesz użyć jednego lub drugiego interfejsu IO, aby zaimplementować ten interfejs wyższego poziomu, ale prawdopodobnie będziesz używać tylko jednego.
Edit: dodanie informacji o zaletach printf
formatowania rodziny funkcji związanych z lokalizacją. Należy pamiętać, że informacje te są ważne tylko dla niektórych implementacji.
Możesz użyć %m$
zamiast %
do odwoływania się do parametru za pomocą indeksu zamiast odwoływania się do nich kolejno. Można to wykorzystać do zmiany kolejności wartości w sformatowanym łańcuchu. Poniższy program zapisze Hello World!
na standardowym wyjściu.
#include <stdio.h>
int main() {
printf("%2$s %1$s\n", "World!", "Hello");
return 0;
}
Rozważ tłumaczenie tego kodu C++:
if (nb_files_deleted == 1)
stream << "One file ";
else
stream << nb_file_deleted << " files ";
stream << removed from directory \"" << directory << "\"\n";
To może być naprawdę trudne. Z printf
(oraz biblioteką jak gettext
aby obsłużyć lokalizację), kod nie jest mieszany z łańcuchem znaków. Możemy więc przekazać ciąg do zespołu lokalizacyjnego i nie będziemy musieli aktualizować kodu, jeśli istnieją specjalne przypadki w jakimś języku (w niektórych język, jeśli liczba obiektów wynosi 0, używasz formy mnogiej, w innym języku istnieją trzy formy jedna dla liczby pojedynczej, jedna, gdy istnieją dwa obiekty i forma mnoga,...).
printf (ngettext ("One file removed from directory \"%2$s\"",
"%1$d files removed from directory \"%2$s\"",
n),
n, dir);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-19 23:20:33
printf
a przyjaciele są okropnie niebezpieczni w porównaniu do <iostream>
i nie mogą być rozszerzane, plus oczywiście {[2] } i przyjaciele nie mają RAII, co oznacza, że jeśli nie udowodnisz profilerem, że zdecydowanie potrzebujesz różnicy wydajności (która udowodniłaś, że istnieje na twojej platformie i w Twoim kodzie), będziesz musiał być idiotą, aby printf
.
Edit: lokalizacja to interesująca rzecz, której nie rozważałem. Nigdy nie zlokalizowałem żadnego kodu i nie mogę skomentować krewnego możliwość lokalizacji printf
i <iostream>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-16 19:57:07
Dla małego projektu hobbystycznego prawdopodobnie wybrałbym bardziej bezpieczne dla typu strumienie C++ io.
Dość zabawne, nigdy nie widziałem nietrywialnego projektu, który używa żadnego z nich. We wszystkich przypadkach używaliśmy abstrakcji zbudowanych na bazie natywnego API OS dla IO.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-16 17:09:47
Nic nie może być uznane za złą praktykę, jeśli ma określony cel. Jeśli IO jest wąskim gardłem programu, to tak, c-style IO działa szybciej niż C++ IO. Ale jeśli tak nie jest, wybrałbym podejście C++ stream. Bo jest ładniejszy:)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-16 17:07:42
Zalety
- bezpieczeństwo typu: typy argumentów operacji strumieniowych w C++ są sprawdzane podczas kompilacji, podczas gdy argumenty
printf
są przekazywane przez...
powodując niezdefiniowane zachowanie, jeśli nie pasują do formatowania. - Zarządzanie zasobami: obiekty strumienia C++ mają destruktory do zamykania uchwytów plików, wolnych buforów i co masz. Strumienie C wymagają zapamiętania wywołania
fclose
.
Wady
- Performance: this oczywiście zależy od implementacji, ale formatowanie strumieni C++ okazało się znacznie wolniejsze niż równoważne formatowanie
printf
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-16 17:19:31
IMHO, prawdziwy Programista C++ stara się robić rzeczy w idiomatyczny sposób C++; konwertowany Programista C stara się trzymać starych sposobów robienia rzeczy. Ma to związek z czytelnością i spójnością.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-16 17:06:47
Po pierwsze, nie musisz najpierw konwertować obiektów C++ (zwłaszcza string
s) do form zgodnych z C.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-16 17:03:41
Czy uważa się za" złą praktykę " Włączanie funkcji C w projekty C++?
Zazwyczaj kod IO pliku powinien być zamknięty w implementacji klasy lub funkcji. Nie uznałbym żadnych wyborów, których dokonujesz w enkapsulowanych implementacjach za "złą praktykę", zastrzegam to określenie dla tego, co wpływa na użytkownika twojej Biblioteki lub kodu (tj. interfejsu). Jeśli ujawniasz mechanizm pliku IO w interfejsie, to IMO to zła praktyka czy używasz funkcji Io stream lub C-style IO.
Powiedziałbym raczej, że funkcje IO W Stylu C są (prawdopodobnie zawsze) gorszym wyborem.
Jakie są zalety korzystania ze strumieni nad dostępem do IO w stylu C?
Po pierwsze, lepiej integrują się ze standardowymi konstrukcjami C++, takimi jak std::string
. Integrują się dość dobrze z STL <algorithms>
. Pozwalają one tworzyć zamknięte operatory odczytu/zapisu (>) tak, aby Twoje niestandardowe klasy wyglądały prawie tak jak prymitywne typy, jeśli chodzi o operacje IO.
Wreszcie, strumienie IO w C++ mogą używać mechanizmu WYJĄTKÓW do zgłaszania błędów w strumieniu lub operacji odczytu/zapisu. Sprawiają one, że kod IO pliku jest znacznie ładniejszy, unikając strasznego wyglądu mechanizmów kodu błędu(Sekwencja instrukcji if i brzydkich pętli while, które sprawdzają kod błędu po każdej operacji).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-16 17:13:55
Ogólnie rzecz biorąc, powinieneś preferować operatory C++, są to:
-- Typ Bezpieczny. Nie ryzykujesz, że zdasz sobowtóra, gdzie format wzywa do int.
-- Extensible. Możesz pisać własne wkładki i ekstraktory i użyj ich.
-- Extensible. Można zdefiniować własne manipulatory (z znaczenie logiczne specyficzne dla aplikacji), i używać ich. Jeśli chcesz zmienić format całego numeru WidgitNumber (wewnętrznie, int) w swoim wyjściu, można Zmień manipulatora; nie musisz znaleźć całego formatu polecenia, gdzie %d jest numerem WidgitNumber.
-- Extensible. Możesz pisać własne umywalki i źródła, a mogą one być przekazywane do innych zlewozmywaków i źródeł, filtrując lub Rozszerzanie wejścia lub wyjścia zgodnie z życzeniem.
(FWIW: chyba nigdy nie napisałem aplikacji, która nie używali niestandardowych > > i
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-16 17:15:57
Czy za" złą praktykę " uważa się Włączanie funkcji C w projekty C++?
Nie. Funkcje C są często używane w projektach C++. Jeśli chodzi o strumienie, na przykład Google C++ Style Guide zaleca używanie ich tylko w ograniczonych przypadkach, takich jak "ad-hoc, lokalne, czytelne dla człowieka i skierowane do innych programistów, a nie Użytkowników końcowych".
Jakie są zalety korzystania ze strumieni nad dostępem do IO w stylu C?
Główne zalety to bezpieczeństwo typu i rozciągliwość. Jednak strumienie C++ mają poważne wady, zobacz Odpowiedzi na to pytanie , takie jak problemy z lokalizacją, słabe raportowanie błędów, nadmiar kodu i problemy z wydajnością w niektórych implementacjach.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:46:38