reklama
Aktuality  |  Články  |  Recenze
Doporučení  |  Diskuze
Grafické karty a hry  |  Procesory
Storage a RAM
Monitory  |  Ostatní
Akumulátory, EV
Robotika, AI
Průzkum vesmíru
Digimanie  |  TV Freak  |  Svět mobilně

Formátovanie C kódu

eraser (0)|20.7.2006 20:54
Ktorý zápis preferujete, prípadne napíšte svoj vlastný, resp. obľúbené formátovanie pre C jazyk.

[ansi]
[CODE]int Foo()
{
if (isBar)
{
bar();
return 1;
}
else
{
return 0;
}
}[/CODE]

[kr]
[CODE]int Foo() {
if (isBar) {
bar();
return 1;
} else {
return 0;
}
}[/CODE]

Mimochodom, aký máte názor na takéto štýly...

[CODE]for (i = 0; i < 10; i++) vs. for(i=0;i<10;i++)[/CODE]
[CODE]for(i = 0; i < 10; i++) vs. for(i=0;i<10;i++)[/CODE]

[CODE]strcpy(buf, str) vs. strcpy (buf, str)[/CODE]
[CODE]strcpy (buf, str) vs. strcpy (buf,str)[/CODE]

Osobne nemám rád zápis funkcie s medzerou medzi názvom funkcie a zátvorkou, dosť ma to pletie, resp. zle to moja lebzna parsuje. Navyše nemám rád, ked sa bez medzery píše keyword napr. for, while,... medzi kľúčovým slovom a zátvorkou. Ďalej neznášam hustenie, čiže pekne medzera medzi parametrami, atd.
Matajon (125)|21.7.2006 16:22
Ja preferuju psani asi takhle :
[CODE]
int Foo()
{
if (isBar)
{
bar();
return 1;
}
else
{
return 0;
}
}[/CODE]
Zda se mi prehlednejsi urcovani, kde ktera "vetev" programu konci a zacina

[CODE]for (int i = 0; i < 10; i++)[/CODE]
Psani bez mezer sux (spatne se to potom cte) :)
eraser (0)|21.7.2006 16:25
Vidno, že v tomto máme rovnaký vkus... horšie je, že to nechce pochopiť pár tupých hláv v našej firme. :)
Matajon (125)|21.7.2006 16:38
[QUOTE=eraser]Vidno, že v tomto máme rovnaký vkus... horšie je, že to nechce pochopiť pár tupých hláv v našej firme. :)[/QUOTE]
OT: To muzou rovnou psat do jednoho radku :rolleyes:
eraser (0)|21.7.2006 16:48
Presne... ono, pre krátku utilitku je to ešte OK, no pre nafúknutú aplikáciu, ktorá má stotisícky riadkov a tisícky súborov, to je skutočný humus.
Architect (232)|21.7.2006 19:45
[QUOTE=eraser]Ktorý zápis preferujete, prípadne napíšte svoj vlastný, resp. obľúbené formátovanie pre C jazyk.

[ansi]
[CODE]int Foo()
{
if (isBar)
{
bar();
return 1;
}
else
{
return 0;
}
}[/CODE]

Jednoznacne prehlednost.

[CODE]for (i = 0; i < 10; i++)[/CODE]

Taktez. Vtomto se clovek orientuje podle me rychleji, nez bez mezer.
[/QUOTE]

Lidi jsou schopní všeho, dokud neudělají rozsáhlejší program, stačí na pár tisíc řádků a používají nevhodné názvy proměných, bez komentářů a navíc tenhle pfujtajblunk bez mezer, odřádkování, prostě humus.
Po měsíci mají přidat nějakou funkci, a protože jsou bez dokumentace, musejí projíždět kód od začátku a většinou to skončí fiaskem a remakem programu od nuly, nebo spousty chybami v projektu...:)
Limoto (162)|21.7.2006 21:53
[quote=Architect]Lidi jsou schopní všeho, dokud neudělají rozsáhlejší program, stačí na pár tisíc řádků a používají nevhodné názvy proměných, bez komentářů a navíc tenhle pfujtajblunk bez mezer, odřádkování, prostě humus.
Po měsíci mají přidat nějakou funkci, a protože jsou bez dokumentace, musejí projíždět kód od začátku a většinou to skončí fiaskem a remakem programu od nuly, nebo spousty chybami v projektu...:)[/quote]myslím, že by se dal sehnat software, kterej by to uspořádal ;)
eraser (0)|22.7.2006 09:18
Architect (232)|22.7.2006 15:03
[QUOTE=Limoto]myslím, že by se dal sehnat software, kterej by to uspořádal ;)[/QUOTE]

Ještě by to chtělo software, který automaticky přidá důležité komentáře:).
Ritchie83 (369)|24.7.2006 20:27
Používám něco na způsob K&R. Mimochodem K&R stylem je psán i Linux.
eraser (0)|29.7.2006 01:07
Čo je to presne za spôsob? Chcelo by to nejaké ukázky.
wojta (54)|29.8.2007 00:50
To pisete v nejakem obycejnem textaku? V eclipse nebo kdevelop je krasne automaticke formatovani. V eclipse se da zvolit dokonce ze tri stylu.
eraser (0)|29.8.2007 22:02
Ja používam SciTE editor.
mrozu (87)|5.9.2007 16:42
Ja pouzivam na C z nostalgickych duvodu MS visual studio, dale pak PSpad.
Formatovani pouzivam takovy mutant mezi K&R a ANSI, podle aktualni chuti :)
Ale hlavni, co me dokaze vytocit je pouzivani mezer misto tabelatoru pri odsazeni radky.
syky001 (6)|5.12.2007 21:38
Protože programuju jak v C(++), tak v Javě, tak jsem sjednotil kodovani nějak takhle
[code]
int Foo() {
if (isBar) {
for (int i = 0; i < 10; i++) {
bar();
}
return 1;
} else {
return 0;
}
}
[/code]
Intri (3490)|5.12.2007 22:21
Osobně používám ANSI, bez něj ani ránu v jakémkoliv programovacím jazyce. Tak nějak jsem si ho osvojil a používám jej ať na PHP, Delphi, Javu, C/C++, C# a kdo ví, co ještě, tak třeba na prachobyčejné HTML. Pokud jde o vývojové prostředí pro C/C++, používám DevC++, které mi taky vyhovuje. K dispozici mám i Visual Studio, ale to je pro mé potřeby zbytečně robustní. Mám ho jen kvůli C#.
a8nr (176)|6.12.2007 21:40
Teď už ANSI. V Úvodu do C jsem používal nějakou zmršeninu na styl K&R kvůli omezení 80 znaků na řádek.
Gianelle (20)|13.4.2008 20:26
Zásadně ANSI, je to přehlednější. Mezery strkám skoro všude, jenom mezi názvem funkce, resp. klíčovým slovem a závorkou mi nějak nešmakujou.
Styryx (351)|14.4.2008 10:45
No jo, každej si používá tak nějak co mu vyhovuje; já osobně zhruba takhle (v C++):

[code]
int Foo( const int param1, const int param2 )
{
if ( !isBar ) {
for ( int i = 0; i < 10; ++i ) {
bar( param1, param2 );
}
return 1;
} else {
return 0;
}
}

// C++:
Foo::Foo( const int param1, const int param2 )
throw()
: m_member1( param1 )
, m_member2( param2 )
{}
[/code]

S těma mezerama v parametrech funkcí to do mě vtloukali kvůli přehlednosti tak jsem u toho zatím zůstal, ale možná to začnu psát bez mezer (protože to tak dělají všichni ostatní a i v Javě je to spíš preferovanej způsob).

Složený závorky píšu na novou řádku jenom u funkcí (to je kvůli hlavičkám), za jinýma příkazama vždycky za, protože to jinak nesmyslně prodlužuje délku kódu (a tak zhoršuje přehlednost) - nesmyslně proto, že složený závorky používám důsledně vždycky, i když je tam jenom jeden příkaz (např. return) takže se nemůže stát, že by počáteční složená chyběla a je teda zbytečný jí dávat na novou řádku.

[QUOTE=eraser;4334]
Mimochodom, aký máte názor na takéto štýly...

[CODE]for (i = 0; i < 10; i++) vs. for(i=0;i<10;i++)[/CODE]
[CODE]for(i = 0; i < 10; i++) vs. for(i=0;i<10;i++)[/CODE]

[CODE]strcpy(buf, str) vs. strcpy (buf, str)[/CODE]
[CODE]strcpy (buf, str) vs. strcpy (buf,str)[/CODE]

[/QUOTE]

[QUOTE=eraser;4488]Vidno, že v tomto máme rovnaký vkus... horšie je, že to nechce pochopiť pár tupých hláv v našej firme. :)[/QUOTE]

No a možná mají svou pravdu, protože nad tim už jsem taky přemejšlel - v současnosti používám tenhle styl (přibližně, dávám tam navíc mezery mezi závorky, ale takhle to je líp vidět):
[code]
strcpy(buf, str)
for (i = 0; i < 10; ++i)
[/code]
ale když se nad tím člověk zamyslí a pořádně se na to podívá, je to nekonzistentní (pokud budem nahlížet na for, while, if jako na názvy funkcí, což bysme v podstatě měli, protože za nima vždycky musí bejt závorka, takže to de facto funkce jsou), takže z logickýho hlediska, pokud bych chtěl být konzistentní, bych měl používat buďto
[code]
strcpy(buf, str)
for(i = 0; i < 10; ++i)
[/code]
nebo
[code]
strcpy (buf, str)
for (i = 0; i < 10; ++i)
[/code]

což je asi to, odkud tyhle "nepochopitelný" styly pramení (ze snahy o logičnost a konzistentnost).


[QUOTE=mrozu;47454]Ale hlavni, co me dokaze vytocit je pouzivani mezer misto tabelatoru pri odsazeni radky.[/QUOTE]

Ono to může mít svůj důvod, já naopak používám zásadně mezery a ne tabulátory. Tabelátory dělají problémy zejména v C a to na některých Unixech (a já programuju i pro mainframe, ten tabelátory ve zrojáku taky nezkousne), takže všechny kódy, který mají tabelátory, si já naopak de-tabelátoruju :) (a MSVC mám nastavený aby vkládal mezery a ne tabelátory pro odsazení).

Ze stejných důvodů (kvůli přenositelnosti) důsledně dbám, aby délka řádky nepřekročila 80 znaků (zejména opět kvůli mainframe, ale je to dobrý i pro přehlednost, člověk nemusí odrolovávat o obrazovku dál když chce vidět konec podmínky).


*) K tomu ++i - používám pre-inkrementaci všude, kde je to možný - není to moc obvyklý, pravda, možná je post-inkrementace z hlediska čitelnosti kódu srozumitelnější, protože se inkrementace provádí až "na konci" cyklu; ovšem pre-inkrementace je rychlejší, při běhu programu, protože se provede rovnou přičtení a "vrací" se výsledek operace. V post-inkrementaci (i++) se musí aktuální hodnota (která se bude vracet jako výsledek operace) nejdřív vložit do vytvořený dočasný proměnný, pak se provede inkrementace a vrátí se dočasná hodnota (kterou je pak potřeba zase zrušit). V tomhle jenoduchým případě (i++) to velmi pravděpodobně zoptimalizuje kompilátor, ale v případě volání např. na třídě (iterátory) už to není tak jistý (zejména v případě předefinovanýho operátoru post-incrementu či post-decrementu, kde je nutný si dočasnou hodnotu vytvořit a vracet hodnotou, tj. přes copy constructor - pokud předefinovávám pre-increment, stačí přičíst a vrátit referenci na aktuální objekt).

Ze stejných (výkonostních) důvodů používám např. binární posuvy místo násobení mocninama 2 - např. místo i*8 píšu i<<3, místo i/8 i>>3 (u dělení je to obzvlášť markantní, je to hodně pomalá operace, stejně jako modulo, který v případě mocnin 2 nahrazuju binárním and - např. místo i%8 je i&0x07); v jedný aplikaci, která potřebovala bejt hodně rychlá, jsem dokonce používal konstrukci (i<<3)+(i<<1) místo i*10 (ale to už docela chce komentář).

(mimochodem, z výkonostního hlediska by byl idelání zápis cyklu např. "for (i = 10; i > 0; --i)" místo "for (i = 0; i < 10; ++i)" (pokud teda vevnitř i nepoužíváme k něčemu, kde záleží na pořadí) - protože porovnání s nulou je rychlejší operace než porovnání s 10 - ono se to totiž v procesoru (AFAIK) dělá tak, že porovnání s nulou se provádí rovnou, kdežto porovnání s 10 je nutný provést tak, že se od aktuální hodnoty odečte 10 a teprve výsledek se opět porovnává s nulou - a dělá se to při každým testování konce cyklu, takže to v zanořených cyklech může bejt výkonostní problém - v C/C++ se tenhle test provádí pokud vím vždycky, např. v Delphi (Pascalu) je to jedno, protože for cyklus se překládá přes nějakou instrukci procesoru, která to počítá sama, z čehož ale taky plyne, že změna i vevnitř cyklu nemá v Pascalu vliv na počet provedení cyklu, kdežto v C lze hodnotu i libovolně měnit a měnit tím počt provádění)
eraser (0)|14.4.2008 15:17
[quote=Styryx;112016]...jsem dokonce používal konstrukci (i<<3)+(i<<1) místo i*10 (ale to už docela chce komentář).[/quote]Bitový posun a súčet ako optimalizovaná aritmetika môže byť súčasť kompilátora, takže je vždy dobré overenie, či to v strojovom kóde nevyzerá práve tak, ako požadujem.

Napr. ja pre optimalizovaný transfer zase používam takúto konštrukciu... :cool: takze, pokiaľ použiješ vhodnú C-lib a funkcia memcpy() je takto optimalizovaná, tak sa nemáš čím trápiť. No a dá sa to využiť i pri kopírovaní reťazcov a taktiež i pri porovnávaní rôznych arrayov.
[code]; optimized transfer
mov ecx, [dwSize]
shr ecx, 2
rep movsd

mov ecx, [dwSize]
and ecx, 3
rep movsb
[/code][quote=Styryx;112016](mimochodem, z výkonostního hlediska by byl idelání zápis cyklu např. "for (i = 10; i > 0; --i)" místo "for (i = 0; i < 10; ++i)"[/quote]Mimochodom, toto sa mi nejako nezdá... skús tieto dva loopy nahodiť do jednoduchého kódu, skompilovať a potom mi sem nahoď spakované .exe, som zvedavý na strojový kód.
Styryx (351)|14.4.2008 18:24
[QUOTE=eraser;112149]Mimochodom, toto sa mi nejako nezdá... skús tieto dva loopy nahodiť do jednoduchého kódu, skompilovať a potom mi sem nahoď spakované .exe, som zvedavý na strojový kód.[/QUOTE]


No upřímně řečeno jsem to nikdy předtim neověřoval, ačkoliv jsem si myslel, že to tak je. Takže jsi mi s tím teď nasadil brouka do hlavy, měl jsem chvíli čas, takže jsem to prubnul.

Dal jsem to do přílohy i se zdrojákem. Jestli něco poznáš z EXE já teda ne (jenom že se binárně liší) ale pomocí /FA v msvc jsem vygeneroval odpovídající ASM listy, jsou v příloze. Obojí je generovaný v release modu se zapnutou optimalizací /O2.

Výsledek je takovej, jak jsem předpokládal, tj. pokud se jde zhora dolků, překládá se to jinak než zdola nahoru a to přesně, jak jsem předtim říkal:
for ( int i = 0; i < LOOP_COUNT; ++i )
se na konci testuje
[code]
cmp esi, 1000000
jl SHORT $L271
[/code]

a pro reverzní smyčku
for ( int i = LOOP_COUNT; i > 0; --i )
se to překládá jako
[code]
test esi, esi
jg SHORT $L271
[/code]

Instrukce cmp pracuje tak, že odečte od prvního parametru hodnotu druhýho (cca jako sub) - třeba zde:
http://faydoc.tripod.com/cpu/cmp.htm
zatímco instrukce test pracuje jako binární and http://faydoc.tripod.com/cpu/test.htm

takže druhej případ (reverzní smyčka) by IMHO měl být rychlejší (pokud předpokládám, že odečítání je delší operace než binární and).


Každopádně je pravda, že rozdíl v takovýmhle jednoduchým případě nebude nějak významnej; je ovšem otázka, jestli už nebude výraznější rozdíl, když by koncová podmínka nebylo konstantní číslo, ale třeba nějaká složitá funkce - něco jako:
[code]
for ( i = 0; i < SomeLongLastingIntegerFunction(); ++i )
for ( i = SomeLongLastingIntegerFunction(); i > 0; --i )
[/code]

tam už by rozdíl moh bejt měřitelnej, pokud se ta funkce bude volat pokaždý na konci cyklu anebo jenom jednou na začátku
např. když ta funkce bude něco jako tohle:
[code]
int SomeLongLastingIntegerFunction()
{
sleep( 3000 ); // Do some long lasting computation.
return 10;
}
[/code]

pokud by to teda nějak nezoptimalizoval překladač.


// EDIT: Tak jsem to ještě ověřil, a i při optimalizaci tam dá compiler v prvním případě volání funkce (před instrukci cmp), což je poměrně dlouhá operace i samo o sobě (samotný volání funkce při každý iteraci cyklu, pokud to neni potřeba), a když je v ní Sleep tak je poměrně dobře poznat rozdíl.
eraser (0)|14.4.2008 19:28
Tak som si to pozrel a vyzerá to, že to kompilátor skutočne optimalizoval. Ak však použijem inštrukciu TEST, ktorá porovnáva registre, tak by mala zabrať 1 cyklus a CMP s registrom a konštantou tiež 1 cyklus, takže som sa pozrel na opcodes.
[code]
00401010 /$ 56 push esi
00401011 |. BE 40420F00 mov esi, 0F4240
00401016 |> 56 /push esi
00401017 |. E8 E4FFFFFF |call 00401000
0040101C |. 83C4 04 |add esp, 4
0040101F |. 4E |dec esi
00401020 |. 85F6 |test esi, esi
00401022 |.^ 7F F2 \jg short 00401016
00401024 |. 5E pop esi
00401025 \. C3 ret
[/code]Tu je jasne vidno, že test esi, esi zaberá 2 bajty, takže teraz sa pozrieme na druhý prípad...
[code]
00401000 /$ 56 push esi
00401001 |. 33F6 xor esi, esi
00401003 |> 56 /push esi
00401004 |. E8 27000000 |call 00401030
00401009 |. 83C4 04 |add esp, 4
0040100C |. 46 |inc esi
0040100D |. 81FE 40420F00 |cmp esi, 0F4240
00401013 |.^ 7C EE \jl short 00401003
00401015 |. 5E pop esi
00401016 \. C3 ret
[/code]... heh, takže nie je o čom, tu je použitý cmp register, konštanta, pričom pre cmp esi sú vyhradené dva bajty opcódov a ešte je tu zapísaná celá konštanta, takže procesor musí pri každej iterácii prechádzať 4 bajty naviac, čo je vlastne 32 bitová konštanta. V tomto prípade je logické, že tvoje tvrdenie ohľadne daných for-cyklov je pravdivé. :thumb
Logout (4018)|14.4.2008 20:02
Ahoj,
no ta pre/postinkrementace a u normalních čísel nevadí
(to zvládne optimalizátor), např. u iterátorů je to ale skutečně
lepší.
Stejně tak cyklus - obzvlášť pokuď to je cyklus 0 to something.Length(). Jen ten příklad co jsi ukázal ale není správně, protože cyklus dolů není n-1 až 0 ale n až 1...
Matyáš
eraser (0)|14.4.2008 23:40
[quote=Logout;112289]Jen ten příklad co jsi ukázal ale není správně, protože cyklus dolů není n-1 až 0 ale n až 1...[/quote]Skorej by som povedal, že je to od n-1 po 0 väčie alebo rovné.
[CODE]
for (i = n-1; i >= 0; i--)
;
[/CODE]
Ale v podstate je to jedno, záleží od použitia "i" a počtu iterácií... tu však išlo o ukázku optimalizácie v prevední na stojový kód. :cool: