Pár otázok na C++

Pár otázok na C++
« kdy: 20. 11. 2020, 23:30:05 »
Ahojte mám pár otázok na STL. Ako donútiť ofstream aby namiesto \n nevkladal platformovo špecifické konce riadkov?

Keď do textového súboru (na platforme windows) ukladám \n, vloží sa automaticky \r\n teda namiesto 1 znaku vloží 2 ASCII znaky (0x0D 0x0A) niekto si povie, že riešim hovadiny, ale ja chcem mať kontrolu nad tým čo ukladám a u tak low level jazyka ako C++ človek očakáva že v základnej knižinici nebude podobná mágia (volitelne nech tam kludne je, ale rád by som mal možnosť to ovplyvniť, chcem aby keď aplikáciu preportujem na linux tak bude mať jednotné na vlas rovnaké chovanie s windows verziou). Viete mi poradiť ako by sa to dalo ovplyvniť? viem že v režime binary to bude ukladať korektne (znak \n ako \n) akurát neviem či mi pri binárnom móde bude fungovať aj ofstream.imbue(znaková sada).

Vopred ďakujem za tipy.

A keď už som založil toto fórum tak sa opýtam aj ďalšiu vec. V C# a Jave existuje trieda StringBuilder určená na spájanie veľkých reťazcov. Mala by ušetriť performance keďže v .NETe sú reťazce immutable a string builder je mutable.

Čo sa používa na spájanie reťazcov v C++? Bude std::string.append dostatočne efektívne aj keď budem spájať dajme tomu 100000 reťazco? Keďže v C++ sú reťazce mutable asi by to nemal byť problém nie? Na stackoverflow programátori odporúčajú na spájanie reťazcov std::stringstream čo je fajn objekt (aj ho občas použijem) ale niekde som čítal že má horší performance. Viem že najlepšie bude alokovať pamať a do pointeru pridať znaky priamo. Ale to je náchylné na chyby hlavne keď sa pracuje s wchar_t alebo inými charmi tak treba prerátavať velkosť a myslieť na znak \0 atď. Takže priamej práci s pamaťou sa chcem podľa možnosti vyhnúť (ak to neni nevyhnutné) a použiť ho len vo výnimočných prípadoch tam kde sa naozaj šetrí každá pikosekunda.

A keď už sme pri tom meraní efektivity čo používate na jej meranie?

1. Používate nejaký vlastný benchmark postavený na std::high_resolution_clock pustené v cykle?

2. alebo profiler?

3. Alebo nejaký špeciálny benchmark?  Ja som našiel toto: https://github.com/chronoxor/CppBenchmark a toto https://github.com/google/benchmark má to cenu kompilovať?
« Poslední změna: 20. 11. 2020, 23:32:26 od fortran1986 »


BoneFlute

  • *****
  • 1 513
    • Zobrazit profil
Re:Pár otázok na C++
« Odpověď #1 kdy: 21. 11. 2020, 00:05:48 »
Ahojte mám pár otázok na STL. Ako donútiť ofstream aby namiesto \n nevkladal platformovo špecifické konce riadkov?

Keď do textového súboru (na platforme windows) ukladám \n, vloží sa automaticky \r\n teda namiesto 1 znaku vloží 2 ASCII znaky (0x0D 0x0A) niekto si povie, že riešim hovadiny, ale ja chcem mať kontrolu nad tým čo ukladám a u tak low level jazyka ako C++ človek očakáva že v základnej knižinici nebude podobná mágia (volitelne nech tam kludne je, ale rád by som mal možnosť to ovplyvniť, chcem aby keď aplikáciu preportujem na linux tak bude mať jednotné na vlas rovnaké chovanie s windows verziou). Viete mi poradiť ako by sa to dalo ovplyvniť? viem že v režime binary to bude ukladať korektne (znak \n ako \n) akurát neviem či mi pri binárnom móde bude fungovať aj ofstream.imbue(znaková sada).

Teda mě přijde, že když vkládáš \n, tak bych očekával platformově závislé chování. A když chci platformově nezávislé, tak budu dávat \x0D, \x0D\x0A, \x0A. A ano, jsem si vědom toho, že to není úplně übr logické, ale skutečně to tak vnímám.

_Jenda

  • *****
  • 500
    • Zobrazit profil
    • https://jenda.hrach.eu/
    • E-mail
Re:Pár otázok na C++
« Odpověď #2 kdy: 21. 11. 2020, 01:11:36 »
A keď už sme pri tom meraní efektivity čo používate na jej meranie?

1. Používate nejaký vlastný benchmark postavený na std::high_resolution_clock pustené v cykle?
Používám tohle
Kód: [Vybrat]
#define GIGA 1000000000L
#define MEGA 1000000L
struct timespec start, end;
void meas(char * desc) {
  clock_gettime(CLOCK_REALTIME, &end);
  uint64_t diff = (GIGA*(end.tv_sec - start.tv_sec) + end.tv_nsec - start.tv_nsec) / MEGA;
  printf("time: %s took %" PRIu64 " ms\n", desc, diff);
  memcpy(&start, &end, sizeof(struct timespec));
}
a obalím tím jednotlivé věci co program dělá (meas("foo")).

Pozor, nějak to nefungovalo na MIPSu a nezkoušel jsem jestli to projde ubsanem.
2. alebo profiler?
perf record, perf report

Re:Pár otázok na C++
« Odpověď #3 kdy: 21. 11. 2020, 08:25:18 »
Pokud chceš prostě spojit 100000 řetězců do jednoho, největší potíž při naivním přístupu  budou podle mě realokace, které se budou vyskytovat vždy když po nějakém počtu přidaných řetězců přeteče kapacita kontejneru, do kterého to sázíš (u std::string určitě, jak je interně implementovaný stringstream si nejsem jistý). Pokud ty spojované řetězce znáš předem, předalokuj si string s kapacitou takovou, aby se tam všechny vešly. Jestli je předem neznáš, zkus použít nějakou specializovanou strukturu jako je třeba rope.

A samozřejmě  benchmarkovat, benchmarkovat, benchmarkovat. S tím ti ale v C++ poradit nedovedu.

Re:Pár otázok na C++
« Odpověď #4 kdy: 21. 11. 2020, 13:40:13 »
Ahojte mám pár otázok na STL. Ako donútiť ofstream aby namiesto \n nevkladal platformovo špecifické konce riadkov?

Keď do textového súboru (na platforme windows) ukladám \n, vloží sa automaticky \r\n teda namiesto 1 znaku vloží 2 ASCII znaky (0x0D 0x0A) niekto si povie, že riešim hovadiny, ale ja chcem mať kontrolu nad tým čo ukladám a u tak low level jazyka ako C++ človek očakáva že v základnej knižinici nebude podobná mágia (volitelne nech tam kludne je, ale rád by som mal možnosť to ovplyvniť, chcem aby keď aplikáciu preportujem na linux tak bude mať jednotné na vlas rovnaké chovanie s windows verziou). Viete mi poradiť ako by sa to dalo ovplyvniť? viem že v režime binary to bude ukladať korektne (znak \n ako \n) akurát neviem či mi pri binárnom móde bude fungovať aj ofstream.imbue(znaková sada).................

prej to funguje i vobráceně :o :o jakože když soubory pak bude ifstream číst v textovým režimu tak zase ty platform specific zakončovadla bude nahrazovat jenom vobyč '\n' :o ;)

nóó takže jestli jako nějak nestěhuješ ty vyrobený soubory mezi různejma platformama tak by to jako nemuselo vadit moc že si tam ve win bude připisovat ty '\r' :) ;)


Re:Pár otázok na C++
« Odpověď #5 kdy: 21. 11. 2020, 14:56:04 »
Teda mě přijde, že když vkládáš \n, tak bych očekával platformově závislé chování. A když chci platformově nezávislé, tak budu dávat \x0D, \x0D\x0A, \x0A. A ano, jsem si vědom toho, že to není úplně übr logické, ale skutečně to tak vnímám.

\r = \x0D
\n = \x0A

Či do texťáku vložíš \n alebo \x0A je úplne jedno (je to to isté) STL ti tam (na platforme windows) namiesto \x0A práskne \x0D\x0A (skúšal som to pre istotu). Ono v retazci máš uložené naozaj len \n (resp \x0A) ale wofstream ti pri ukladaní do súboru pridá pred \n aj \r.

Citace: Jenda
...

Ďakujem vyskúšam. Porovnám s mojim riešením. :)

Citace: registrovany_ava
...

jo tiež sa snažím predalokovať velkosť (ak sa to dá), ale nie vždy sa to dá.

Citace: Wrána
prej to funguje i vobráceně :o :o jakože když soubory pak bude ifstream číst v textovým režimu tak zase ty platform specific zakončovadla bude nahrazovat jenom vobyč '\n' :o ;)

nóó takže jestli jako nějak nestěhuješ ty vyrobený soubory mezi různejma platformama tak by to jako nemuselo vadit moc že si tam ve win bude připisovat ty '\r' :) ;)

Ale môžu nastať aj situácie kedy chceš mať možnosť voľby medzi \n a \r\n napríklad ak by si programoval editor, alebo konvertor. Preto ma zaujíma či má tento problém nejaké jednoduché riešenie. Neni to pre mňa teraz otázka života a smrti :D, ale raz možno bude. Robím si totiž takú sadu helperov nad STL a tie chcem mať podľa možnosti čo najuniverzálnejšie.

Re:Pár otázok na C++
« Odpověď #6 kdy: 21. 11. 2020, 16:04:46 »
Co otevřít ten stream v binárním režimu místo textového?

nula

Re:Pár otázok na C++
« Odpověď #7 kdy: 21. 11. 2020, 16:40:51 »
1) V norme jazyka je definovane ze \n znamena new-line. Neni tam nic o tom, ze by to melo znamenat LF.
Pokud chces zapisovat vyslovene x0A, tak to samozrejme muzes delat rucne. Jazyk s tim problem nema.
Mnohem casteji nez zapisovat nejake arbitrary znaky chces proste ukoncit radek. Takze je to za mne i logicke reseni.

2) Jednoduche a obvykle dostatecne rychle je proste normalni appendovani ke stringu. Realokace se deji vzdy na dvojnasobek, nebo velikost noveho stringu, podle toho co je vetsi. Tedy vetsinou nerealokujes tolikrat, kolikrat pridavas. Stat se to ofc muze pri supernevhodne rade, kterou spojujes. Kdyz znas vyslednou velikost, tak se zvetseni kapacity samozrejme oplati udelat manualne.

Co je treba rict je, ze castokrat by slo udelat vsechny stringove konkatenace uz v compiletimu. Bohuzel z mne neznamych duvodu std::string neni kompletne constexpr (nejspis opomenuti), takze to na standardnim std::stringu nepoujde. Vyjimecne tedy, pri maximalni optimalizaci, se oplati pouzivat i jine nez implementace, nez ty ze STL.

BoneFlute

  • *****
  • 1 513
    • Zobrazit profil
Re:Pár otázok na C++
« Odpověď #8 kdy: 21. 11. 2020, 17:43:22 »
STL ti tam (na platforme windows) namiesto \x0A práskne \x0D\x0A (skúšal som to pre istotu).
Tak to už je podraz.

nula

Re:Pár otázok na C++
« Odpověď #9 kdy: 21. 11. 2020, 19:17:09 »
STL ti tam (na platforme windows) namiesto \x0A práskne \x0D\x0A (skúšal som to pre istotu).
Tak to už je podraz.

Dalsi takovy, hosi mne z vas klepne.
V NORME jazyka C je definovane UMYSLNE, ze znak \n v TEXTOVEM modu znamena NOVY RADEK. Proto se da psat multiplatformne jednoduse:
Kód: [Vybrat]
printf("Hello\nWorld");A vysledek bude na vsech systemech:
Kód: [Vybrat]
Hello
World

A nebude tam neco ve smyslu
Kód: [Vybrat]
Hello
       World
nebo
Kód: [Vybrat]
Hello?World


Tohle bylo zavedeno umyslne, protoze hodne casto potrebujes proste vypsat neco po radcich a fakt te nezajima binarni reprezentace, ale to, jak to vizualne v danem systemu vypada.
Pokud chces binarne presnou reprezentaci, tak pouzivas BINARNI zapis (to je jedna z uplne prvnich veci kterou se snad clovek musi naucit o IO).

Konec radku je na ruznych systemech velmi ruzny:
CR, CRLF, LF, LFCR, dokonce mam pocit ze se na to pouzivaly i jine znaky z ASCII.

V dobe kdy C vznikal bylo toto zcela normalni a jazyk ktery neumi do konzole jednoduse vypsat 2 radky, je absurdne nemultiplatformni. Takze to ma velmi dobry duvod.

Re:Pár otázok na C++
« Odpověď #10 kdy: 21. 11. 2020, 22:39:29 »
STL ti tam (na platforme windows) namiesto \x0A práskne \x0D\x0A (skúšal som to pre istotu).
Tak to už je podraz.
Dalsi takovy, hosi mne z vas klepne. ........................
nóó ale stejně je takový zajímavý žeto c++kový '\n' je schodný zrovinka se zakončením řádku v linuxu. bych se taky jako mohla zeptat proč jinde potřebujou mit něco extra a jestli to jako dneska ještě vůůůbec dává nějakej smysl :P :P ;D ;)

BoneFlute

  • *****
  • 1 513
    • Zobrazit profil
Re:Pár otázok na C++
« Odpověď #11 kdy: 21. 11. 2020, 22:54:29 »
STL ti tam (na platforme windows) namiesto \x0A práskne \x0D\x0A (skúšal som to pre istotu).
Tak to už je podraz.

Dalsi takovy, hosi mne z vas klepne.

Mě zase z tebe. Že neumíš číst. Argumentuješ tu přesně to samé co jsem psal já. Úžasné.

nula

Re:Pár otázok na C++
« Odpověď #12 kdy: 23. 11. 2020, 09:42:54 »
STL ti tam (na platforme windows) namiesto \x0A práskne \x0D\x0A (skúšal som to pre istotu).
Tak to už je podraz.

Dalsi takovy, hosi mne z vas klepne.

Mě zase z tebe. Že neumíš číst. Argumentuješ tu přesně to samé co jsem psal já. Úžasné.

Omlouvam se, sypu si popel na hlavu. Preskocil jsem prispevek od fortrana a to cos citoval nebylo jasne, ze se nevztahuje porad k \n. Tedy, dosel jsem k nazoru, ze to tak je.

Takze uznavam, jsem mamlas, ze jsem si to neprecet poradne. Nicmene porad plati to o tom binarnim rezimu.

BoneFlute

  • *****
  • 1 513
    • Zobrazit profil
Re:Pár otázok na C++
« Odpověď #13 kdy: 23. 11. 2020, 18:58:25 »
STL ti tam (na platforme windows) namiesto \x0A práskne \x0D\x0A (skúšal som to pre istotu).
Tak to už je podraz.

Dalsi takovy, hosi mne z vas klepne.

Mě zase z tebe. Že neumíš číst. Argumentuješ tu přesně to samé co jsem psal já. Úžasné.

Omlouvam se, sypu si popel na hlavu. Preskocil jsem prispevek od fortrana a to cos citoval nebylo jasne, ze se nevztahuje porad k \n. Tedy, dosel jsem k nazoru, ze to tak je.

Takze uznavam, jsem mamlas, ze jsem si to neprecet poradne. Nicmene porad plati to o tom binarnim rezimu.

+1

Re:Pár otázok na C++
« Odpověď #14 kdy: 24. 11. 2020, 16:47:47 »
nóó ale stejně je takový zajímavý žeto c++kový '\n' je schodný zrovinka se zakončením řádku v linuxu. bych se taky jako mohla zeptat proč jinde potřebujou mit něco extra a jestli to jako dneska ještě vůůůbec dává nějakej smysl :P :P ;D ;)
Jestli dneska ještě něco vůbec dává smysl je vedlejší, protože zpětná kompatibilita, žeáno. Wokna mají CRLF protože to tak měl DOS a ten, protože to tak mělo CP/M a ten, protože to tak chtěly staré teletextové mašiny. Jabčáci měli původně CR, ale ti se nekompatibilních změn evidentně nebojí, tak přešli na Unixové LF. U Microsoftu změna nehrozí, tam občas neopravují ani bugy ale přidávají nová rozhraní, protože by opravou rozbili háky, co ty bugy obcházejí.