C - printf împotriva cout în c, cod q - un rus (en)

[15.1] De ce ar trebui să folosesc în loc de tradiționale ?

Promovează siguranța clasei, reduce erorile, permite extensibilitatea și oferă moștenire.







printf (). eventual nu rupte, și scanf (). probabil, potrivit pentru viata, chiar daca este predispus la erori, dar ambii sunt limitate la ceea ce C ++ I / O poate face C ++ I / O (folosind <<и>>) este relativ la C (folosind printf () și scanf ()):

  • Un tip mai sigur: folosind Tipul obiectului care este I / O'd este cunoscut în mod static ca un compilator. Dimpotrivă, folosește câmpurile "%" pentru a defini dinamic tipurile.
  • Mai puține erori: utilizarea nu există jetoane inutile "%" care trebuie să se potrivească cu obiectele reale care sunt I / O. Eliminarea redundanței elimină clasa de erori.
  • Extensibilitate: mecanism C ++ vă permite să introduceți tipuri personalizate de I / O'd fără a întrerupe codul existent. Imaginați-vă haosul, dacă toată lumea a adăugat simultan câmpuri incompatibile "%" în printf () și scanf ().
  • Moștenit: mecanismul C ++ Este construit din clase reale, cum ar fi std :: ostream și std :: istream. spre deosebire de 'FILE *. acestea sunt clase reale și, prin urmare, moștenite. Acest lucru înseamnă că puteți avea și alte lucruri definite de utilizator care arată și se comportă ca fire, dar încă fac ceva ciudat și minunat. Puteți utiliza automat linii de șiruri de caractere I / O scrise de utilizatori pe care nici măcar nu le cunoașteți și nu trebuie să știe despre clasa "avansate".

Sunt surprins că toată lumea din această întrebare susține că std :: cout este mai bun decât printf. chiar dacă întrebarea tocmai a pus o întrebare despre diferențele. Acum există o diferență - std :: cout este C ++, și printf este C (dar o poți folosi în C ++, ca orice altceva cu C). Acum, voi fi cinstit aici; Atât printf cât și std :: cout au avantajele lor.

extensibilitate

std :: cout este extensibil. Știu că oamenii vor spune că printf se extindă, dar această expansiune nu este menționată în standardul C (deci va trebui să utilizați non-standard, dar nu există nici funcții generale non-standard), iar aceste extensii sunt una (atât de ușor să intre în conflict cu un format existent) .

Spre deosebire de printf. std :: cout depinde în totalitate de Reacoperirea, astfel încât nu există probleme cu formate personalizate - tot ceea ce faci, este definiția unui subprogram în care std :: ostream este primul argument, și tipul - al doilea. Astfel, nu există probleme cu spațiul de nume, pentru că aveți o clasă (care nu se limitează la un singur caracter), puteți avea pentru std :: ostream de suprasarcină std :: ostream.

Cu toate acestea, mă îndoiesc că mulți oameni vor dori să se extindă ostream (pentru a fi sincer, eu rareori am văzut astfel de extensii, chiar dacă sunt ușor de făcut). Totuși, este aici dacă aveți nevoie de ea.

După cum puteți vedea, atât printf, cât și std :: cout utilizează o sintaxă diferită. printf folosește sintaxa standard a unei funcții folosind șirul de șablon și listele de argumente cu lungime variabilă. De fapt, printf este motivul pentru care C le are - formatele printf sunt prea complexe pentru a fi utilizate fără. Cu toate acestea, std :: cout utilizează un alt operator API <

De obicei, aceasta înseamnă că versiunea C va fi mai scurtă, dar în majoritatea cazurilor nu contează. Diferența este evidentă atunci când imprimați multe argumente. Dacă trebuie să scrieți ceva de genul Eroare 2: Fișierul nu a fost găsit. Presupunând un număr de eroare și descrierea sa este un substituent, codul va arăta astfel. Ambele exemple funcționează în același mod (bine, cum ar fi std :: endl de fapt reseta tamponul).

Deși acest lucru nu pare prea nebun (este doar de două ori mai mare), totul devine mai nebun când formulezi argumentele și nu doar le tipi. De exemplu, tipărirea ceva de genul 0x0424 este doar nebună. Acest lucru este cauzat de starea de amestecare std :: cout și de valorile reale. Nu am văzut niciodată o limbă în care ceva ca std :: setfill ar fi un tip (cu excepția lui C ++, desigur). printf separă clar argumentele și tipul real. Aș prefera să păstrez versiunea printf (chiar dacă pare destul de criptică) în comparație cu versiunea sa de iostream (deoarece conține prea mult zgomot).

Acesta este avantajul real al printf. Șirul de formate printf este bun. line. Acest lucru face ca traducerea să fie foarte simplă, în comparație cu operatorul <<злоупотребление iostream. Предполагая, что функция gettext() переводится, и вы хотите показать Error 2: File not found. Код для перевода ранее показанной строки формата будет выглядеть так:

Acum, să presupunem că ne traducem la Fiction, unde numărul de eroare este după descriere. Șirul convertit va arăta ca% 2 $ s oru% 1 $ d. \ N Acum, cum să faceți acest lucru în C ++? Nu am idee. Cred ca poti face un iostream fals care construieste printf pe care poti pasa gettext sau altceva in scopuri de traducere. Desigur, $ nu este un standard C, dar este atât de comun încât, în opinia mea, este sigur de utilizat.

Nu trebuie să vă amintiți / căutați o sintaxă specială de tip întreg

Nu puteți imprima un octet NUL, \ 0

Deoarece printf folosește șiruri C, nu șiruri C ++, nu poate imprima octeți NUL fără trucuri speciale. În unele cazuri, puteți utiliza% c cu "\ 0" ca argument, deși acest lucru este în mod clar un hack.

idee

Actualizare. Se pare că iostream este atât de lent încât este de obicei mai lent decât unitatea hard disk (dacă redirecționați programul la un fișier). Dezactivarea sincronizării cu stdio poate ajuta dacă trebuie să afișați o cantitate mare de date. Dacă performanța este o problemă reală (spre deosebire de scrierea mai multor rânduri în STDOUT), trebuie doar să utilizați printf.

Puteți observa cu ușurință că două linii și două (un număr) sunt plasate ca argumente printf. Asta e tot; Nu este nimic altceva. Pentru comparație, iostream este compilat pentru construire. Nu, nu există nici o incrustație; Fiecare operator <





Cu toate acestea, pentru a fi sincer, acest lucru nu înseamnă nimic, deoarece I / O este în orice caz blocaje. Am vrut doar să arăt că iostream nu este mai rapid, pentru că este un tip sigur. Cele mai multe implementări de C pune în aplicare formate printf folosind Goto calculat, funcționează atât de printf la fel de repede cum poate fi, chiar dacă compilatorul nu știe despre printf (nu că ele nu sunt), unele compilatoare pot optimiza printf în anumite cazuri - constanta o linie care se termină în \ n este, de obicei, optimizată pentru a pune).

moștenire

Nu știu de ce ai vrea să moșteni ostream. dar nu-mi pasă. Acest lucru este posibil și pentru FILE.

Tip de garanție

Adevărat, listele de argumente cu lungime variabilă nu sunt sigure, dar nu contează, deoarece compilatoarele populare C pot detecta probleme cu șirul de format printf. dacă includeți avertismente. De fapt, Clang poate face acest lucru fără a porni avertismentele.

Condițiile de nivel înalt, diferențele principale sunt siguranța de tip (cstdio are), performanța (cele mai multe implementari ale iostreams mai lent decât cstdio) și extensibilitate (iostreams vă permite să personalizați țintele de ieșire și se potrivește perfect afișa anumite tipuri de utilizator).

Oamenii spun adesea că printf este mult mai rapid. Acesta este cam un mit. Tocmai am testat-o, cu următoarele rezultate:

Concluzie: dacă doriți doar linii noi, utilizați printf; În caz contrar, cout va fi aproape la fel de rapid sau chiar mai rapid. Mai multe informații pot fi găsite în blogul meu.

Pentru a fi clar, nu încerc să spun că iostream este întotdeauna mai bun decât printf; Vreau doar să spun că trebuie să luați o decizie în cunoștință de cauză bazată pe date reale, și nu o ipoteză sălbatică bazată pe o presupunere comună, înșelătoare.

Actualizare: aici este codul complet pe care l-am folosit pentru testare. Compilate cu g ++ fără alte opțiuni (cu excepția -lrt pentru sincronizare).

Una dintre ele este o funcție care imprimă la stdout. Un alt obiect care oferă multiple funcții ale membrilor și supraîncărcări ale operatorilor<<которые печатаются в stdout. Есть еще много различий, которые я мог бы перечислить, но я не уверен, что вам нужно.

Pentru mine, diferențele reale care ar face să trec la "cout", nu "printf":

1) <<оператор может быть перегружен для моих классов.

3) Mi se pare mult mai ușor de citit, mai ales când avem mulți parametri.

Una dintre problemele cu cout este opțiunile de formatare. Formatul de date (precizie, corectitudine etc.) În printf este mai ușor.

Două puncte care nu sunt menționate aici altfel, mi se pare semnificativă:

1) Cout poartă o mulțime de bagaje, dacă nu utilizați deja STL. Se adaugă codul de două ori mai mare pentru fișierul dvs. de obiect ca și printf. Acest lucru este valabil și pentru șir. și acesta este motivul principal pentru care tind să folosesc propria mea bibliotecă de șir.

2) cout utilizează supraîncărcat <<операторы, которые я нахожу неудачными. Это может добавить путаницу, если вы также используете оператор <<по своему назначению (сдвиг влево). Я лично не люблю перегружать операторов для целей, имеющих тангенциальное значение для их предполагаемого использования.

Rezultat: Voi folosi cout (și șir) dacă folosesc deja STL. În caz contrar încerc să evit asta.

Cu primitivi, probabil că nu contează ce folosiți. Spun unde este util când vrei să afișezi obiecte complexe.

De exemplu, dacă aveți o clasă,

Este posibil ca cele de mai sus să nu pară foarte bune, dar să presupunem că trebuie să afișați acest lucru în mai multe locuri din codul dvs. Nu numai acest lucru, de exemplu, adăugați câmpul "int d". Cu cout, trebuie doar să îl schimbați într-un singur loc. Cu toate acestea, cu printf, va trebui să îl schimbați în cât mai multe locuri posibil și nu numai că, trebuie să vă reamintiți pe care dintre dvs. să le scoateți.

Acestea fiind spuse, folosind cout, puteți reduce o mulțime de timp petrecut pe menținerea codului, nu doar faptul că, dacă reutilizați un „ceva“ obiect în noua aplicație, nu într-adevăr nevoie să vă faceți griji cu privire la ieșire.

Aș vrea să spun că lipsa de extensibilitate a printf nu este în întregime adevărată:
În C este adevărat. Dar în C nu există clase reale.
În C ++, puteți supraîncărca operatorul de distribuție, suprasolicitând astfel operatorul char * și folosind printf după cum urmează:

Poate fi posibil ca Foo să supraîncărcă un bun operator. Sau dacă ați făcut o metodă bună. Pe scurt, printf este la fel de extensibil ca și cout pentru mine.

Argumentul tehnic pe care îl pot vedea pentru fluxurile C ++ (în general, nu doar pentru cout.):

Siguranța tipului. (Apropo, dacă vreau să imprimați un singur „\ n“, folosesc putchar ( „\ n“). Nu voi folosi o bombă nucleară pentru a ucide insecte.).

Mai ușor de învățat. (Nu există parametri "complexi" pentru învățare, operatorii sunt ușor de folosit <<и>>)

Lucrați cu std :: string (pentru printf există std :: string :: c_str (). Dar pentru scanf?)

Pentru printf, văd:

Mai ușor sau cel puțin mai scurt (în ceea ce privește scrierea de caractere) formatare complexă. Mult mai ușor de citit, pentru mine (o chestiune de gust, cred).

Un control mai bun care fac funcția (sau, mai degrabă, cât de multe personaje au fost scrise, și% n formatorului: «Nu se imprimă nimic Argumentul trebuie să fie un pointer la un int semnat, care păstrează numărul de caractere scrise până în prezent» (De la printf - C ++ de referință)

Cea mai bună opțiune de depanare. Din același motiv ca ultimul argument.

Preferința mea personală scanf funcțiile printf (și scanf), mai ales pentru că îmi place liniile scurte, și pentru că eu nu cred că tipul de probleme de imprimare atunci când se imprimă foarte greu de evitat. Singurul lucru pe care îl condamn cu funcții în stil C este că std :: string nu este acceptat. Noi trebuie să treacă char * înainte de std :: string :: c_str () printf lui (cu std :: string :: c_str () dacă vrem să citească, dar cum să scrie?)

Alte diferențe: "printf" returnează o valoare întreagă (egală cu numărul de caractere tipărite) și "cout" returnează nimic

cout <<"y = " <<7; Не является атомарным.

printf ("% s =.", "y", 7); Este atomic.

Cout nu verifică tipul, printf nu.

Nici un echivalent cu iostream "% d"

Desigur, puteți scrie "ceva" un pic mai bun pentru a menține serviciul:

Aș dori să subliniez că dacă vrei să joci fluxuri în C ++, dacă folosești cout poți obține rezultate interesante.

Luați în considerare acest cod:

Acum ieșirea este amestecată. De asemenea, poate da rezultate diferite, încercați de mai multe ori:

Puteți folosi printf pentru selecția corectă sau puteți utiliza mutex.

Ele sunt folosite pentru imprimarea valorilor. Ei au o sintaxă complet diferită. C ++ are ambele, C are doar PRINTF.

Nu sunt un expert. doar sa întâmplat să aud doi angajați vorbesc despre cum ar trebui să evite utilizarea de C ++ în domeniul sistemelor integrate din motive de performanță. Ei bine, destul de interesant, am făcut testul bazat pe sarcina reală a proiectului.

În această sarcină, a trebuit să scriem o configurație în RAM. Ceva ca:

cafeaua = fierbinte
zahăr = nr
lapte = sân
mac = AA: BB: CC: DD: EE: FF

M-am străduit să le lustruiesc înainte de a le rupe de 100.000 de ori. Iată rezultatele:

Dimensiunea fișierului obiect:

Concluzie: Pe platforma mea foarte specifică. cu un procesor foarte specific. rulează o versiune foarte specifică a kernel-ului Linux. pentru a porni programul. care este compilat cu o versiune foarte specifică a GCC. pentru asta. să îndeplinească o sarcină foarte specifică. Aș spune. Abordarea C ++ este mai potrivită. Funcționează mult mai rapid și oferă o lizibilitate mult mai bună. Pe de altă parte, C oferă o zonă mică, după părerea mea, nu înseamnă aproape nimic. deoarece mărimea programului nu este preocuparea noastră.

Nu sunt programator, dar eram inginer de factori umani. Simt că limba de programare ar trebui să fie ușor de învățat, înțeleasă și folosită și necesită o structură lingvistică simplă și consistentă. Deși toate limbile sunt simbolice și, astfel, în mod inerent arbitrare, există acorduri și respectarea acestora face limba mai ușor de a învăța și de utilizare.

În Python, noi, desigur. Puteți imprima și utilizând o sintaxă destul de obișnuită a obiectului.metodă, adică variablename.print, deoarece variabilele sunt obiecte, dar în C ++ acestea nu sunt.

Nu-mi place sintaxa pentru că <<оператор не следует никаких правил. Это метод или функция, т.е. принимает параметр и делает что-то для него. Однако написано, как если бы это был математический оператор сравнения. Это плохой подход с точки зрения факторов человека.

printf () este o funcție atunci cout este o variabilă.







Articole similare

Trimiteți-le prietenilor: