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?

Author: gablin, 2011-03-16

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);
 39
Author: Sylvain Defresne,
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>

 8
Author: Puppy,
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.

 6
Author: Nemanja Trifunovic,
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:)

 5
Author: Armen Tsirunyan,
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.
 5
Author: Mike Seymour,
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ą.

 4
Author: grokus,
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 strings) do form zgodnych z C.

 3
Author: geekosaur,
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).

 3
Author: Mikael Persson,
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

 3
Author: James Kanze,
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.

 3
Author: vitaut,
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