Fórum Root.cz

Hlavní témata => Vývoj => Téma založeno: Buggy 06. 04. 2013, 11:28:09

Název: Štábní kultura C a preprocesor
Přispěvatel: Buggy 06. 04. 2013, 11:28:09
Zdravim,
rad bych znal nazor zkusenych (pak si snad dojdu k obecnemu zaveru z medianu ;-)) - jak formatovat symbolicke konstanty, jak hojne je pouzivat? Dodavam, ze mi jde o kod urceny pro svet embedded...

1/ urcite je vice nez vhodne zavorkovat makra, ale je rozumne tak i pro konstanty?
Kód: [Vybrat]
#define SUM(a,b) (a+b)  /* OK s ohledem na pouziti v kodu a prioritu operatoru */
#define MAX      (100U) /* nadbytecne zavorky, zneprehledneni mezi-kodu zpracovaneho preprocesorem */

2/ o vyuziti symbolicke konstanty napr. pro maximum neni asi pochyb, ale je to vhodne i v nasledujicim?
Kód: [Vybrat]
#define EMPTY_BUFFER 0U

while(length-- > EMPTY_BUFFER)
  foo();

Opomenme mozna elegantnejsi (mluvime o embedded, tedy vetsi "explicitnost" - MISRA aspol.) zapis
Kód: [Vybrat]
while(length--) - v tomto pripade kompilator (asi) vygeneruje stejny assembler pro oba zapisy.

Neni ve finale "citelnejsi":
Kód: [Vybrat]
while(length-- > 0U)
  foo();
Název: Re:Stabni kultura C - preprocesor
Přispěvatel: jano 06. 04. 2013, 11:48:20
IMHO
1. zátvorkovať tak aby z toho nevznikali výsledky ktoré sú neočakávané takže:
Kód: [Vybrat]
#define SUM(a,b) (a+b) // čo asi vznikne z SUM(9<<2,5)namiesto toho bude lepšie:
Kód: [Vybrat]
#define SUM(a,b) ((a)+(b))aj keď najlepšie je použiť inline funkcie aby sa predišlo situácii:
Kód: [Vybrat]
#define MAX(a,b) (a>b?a:b)
c = MAX(i++,0) // aký je obsah premenných i a c??
2. tie kódy niesú ekvivalentné
Kód: [Vybrat]
while(length--) // sa znamená: while (length-- != 0)
Název: Re:Stabni kultura C - preprocesor
Přispěvatel: Logik 06. 04. 2013, 12:41:54
Makra závorkovat tak, aby nedošlo k špatné interpretaci.

Konstanty bych nedefinoval makrem, ale pomocí const. Vede to k čitelnějšímu a víc failproof kódu.

Konstanty bych zaváděl tam, kde znamenají nějakou pevnou hodnotu (např. přepínače apod.). Velikosti bufferu bych zpravidla zaváděl jako variabilní, tady bych konstantu použil max jako defaultní parametr. Konstanta pro nulu v uvedeném zápisu je pak IMHO blbina - na tom místě nemá žádný jiný číslo než nula smysl - zavádět tam konstantu mi přijde podobný, jako dělat for cyklus stylem:

for(x=CONSTZERO;x<delka; x+=CONSTONE)  ...
Název: Re:Stabni kultura C - preprocesor
Přispěvatel: student 06. 04. 2013, 13:41:07
Kód: [Vybrat]
while(length-- > 0U)
  foo();
To sa naozaj dlzka zmensuje? Ja by som radsej pouzil prehladnejsie:

Kód: [Vybrat]
for(unsigned int position = 0; position < length; position++) {
  foo(position);
}
To by bolo jednoznacne citatelnejsie a bolo by jasne, co to robi; pretazovat "length" na urcenie pozicie moze viest akurat tak k nenapadnym bugom.
Název: Re:Stabni kultura C - preprocesor
Přispěvatel: Logik 06. 04. 2013, 16:52:18
student: ale není to tak efektivní. Protože porovnávání na nulu neotřebuje nahrávat další paměťovou lokaci. Nicméně souhlasím, že název "length" tu není úplně to pravý.
Název: Re:Stabni kultura C - preprocesor
Přispěvatel: Natix 06. 04. 2013, 20:29:08
Pánové, já nejsem céčkař, ale nedefinujete sum(a, b) jako funkci, ale cpete to do preprocesoru? To je nějaká černá magie?
Název: Re:Stabni kultura C - preprocesor
Přispěvatel: Jarek 06. 04. 2013, 21:03:52
Pánové, já nejsem céčkař, ale nedefinujete sum(a, b) jako funkci, ale cpete to do preprocesoru? To je nějaká černá magie?
Má to být embedded a tam to v určitých okrajových případech může mít smysl. Nicméně většina překladačů rozumí i klíčovému slovu inline ;).
Název: Re:Stabni kultura C - preprocesor
Přispěvatel: anonym 06. 04. 2013, 21:26:59
Má to být embedded a tam to v určitých okrajových případech může mít smysl. Nicméně většina překladačů rozumí i klíčovému slovu inline ;).

a rozumnej prekladac na nej kasle (nebo ho pouziva jako drobny hint), protoze sam dobre vi kde se vyplati a kde ne...

Pánové, já nejsem céčkař, ale nedefinujete sum(a, b) jako funkci, ale cpete to do preprocesoru? To je nějaká černá magie?
proc se to dela jako makro je protoze C (bez compiler-specific rozsireni) nema overloading podle agrumentu, takze si nemuzu napsat nekolik funkci sum() pro ruzne velke argumenty (a automaticky casting na nejvetsi dostupny typ nechci, protoze embedded). je sance ze kompilator udela inline a potom uvidi ze casty nejsou potreba, ale na to uz bych tolik nevsazel
Název: Re:Stabni kultura C - preprocesor
Přispěvatel: Pavel Tisnovsky 06. 04. 2013, 21:27:50
Pánové, já nejsem céčkař, ale nedefinujete sum(a, b) jako funkci, ale cpete to do preprocesoru? To je nějaká černá magie?

Takhle je mozne makro sum() - podotykam ze dobre "uzavorkovane" - pouzit pro ruzne datove typy, takze v embedded oblasti treba bajty (unsigned char...). Taky se usetri tanecky okolo predavani a vraceni parametru...
Název: Re:Stabni kultura C - preprocesor
Přispěvatel: Jarek 06. 04. 2013, 21:58:02
proc se to dela jako makro je protoze C (bez compiler-specific rozsireni) nema overloading podle agrumentu, takze si nemuzu napsat nekolik funkci sum() pro ruzne velke argumenty
Největší nevýhodou čehokoliv v preprocesoru je nulová typová kontrola, takže klidně můžu zavolat
Kód: [Vybrat]
sum(long, char)
nebo třeba ještě zábavnější:
Kód: [Vybrat]
#define sub(a, b) (a - b)
char* x = &nejaka_promenna;
char* y = &nejaka_jina_promenna;
sub(x, y)
Když budu mít normální funkci, tak mi překladač řekne, že se snažím nacpat long do char nebo pointer do char, což jsem asi nechtěl. Preprocesor patří k těm temnějším stránkám céčka, už jsem viděl pár ošklivých bugů způsobených nadbytečným používáním preprocesoru a nikdy nebylo použití preprocesoru nutné a dalo se to udělat i normálně.
Název: Re:Stabni kultura C - preprocesor
Přispěvatel: Natix 06. 04. 2013, 22:03:05
Díky. Opět jsem si ověřil, že C není nic pro mě.  ;)
Název: Re:Stabni kultura C - preprocesor
Přispěvatel: prezek 06. 04. 2013, 23:58:31
Jarek: a co je špatného na:
Kód: [Vybrat]
#define sub(a, b) (a - b)
char* x = &nejaka_promenna;
char* y = &nejaka_jina_promenna;
sub(x, y)
?
Název: Re:Stabni kultura C - preprocesor
Přispěvatel: Jarek 07. 04. 2013, 00:19:30
Jarek: a co je špatného na:
Kód: [Vybrat]
#define sub(a, b) (a - b)
char* x = &nejaka_promenna;
char* y = &nejaka_jina_promenna;
sub(x, y)
?
Celkem nic špatného na tom není, akorát to bude od sebe odčítat pointery x a y místo proměnných nejaka_promenna a nejaka_jina_promenna. Kdybych mel funkci:
Kód: [Vybrat]
char sub(char a, char b);
a zavolal ji podle toho příkladu nahoře, tak mi překladač vynadá, že neví, jak má zkonvertovat char* na char a nepřeloží to. Když sub udělám makrem, tak se to přeloží bez chyb a dokonce to bude i něco počítat, ale asi ne to, co autor kódu zamýšlel.

Jinak pro embedded věci existují docela dobré coding standards:
http://www.stroustrup.com/JSF-AV-rules.pdf (http://www.stroustrup.com/JSF-AV-rules.pdf)
Použili to v Lockheed Martin na vývoj nějaké stíhačky. Doporučuju přečíst 4.6.2 #define Pre-Processing Directive
Název: Re:Stabni kultura C - preprocesor
Přispěvatel: JS 07. 04. 2013, 08:51:21
Jarek: a co je špatného na:
Kód: [Vybrat]
#define sub(a, b) (a - b)
char* x = &nejaka_promenna;
char* y = &nejaka_jina_promenna;
sub(x, y)
?

No IMHO by asi bylo lepe psat:
Kód: [Vybrat]
#define sub(a, b) ((a) - (b))