Štábní kultura C a preprocesor

Buggy

Štábní kultura C a preprocesor
« kdy: 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();
« Poslední změna: 08. 04. 2013, 10:45:35 od Petr Krčmář »


jano

Re:Stabni kultura C - preprocesor
« Odpověď #1 kdy: 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)

Logik

  • *****
  • 1 047
    • Zobrazit profil
    • E-mail
Re:Stabni kultura C - preprocesor
« Odpověď #2 kdy: 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)  ...

student

Re:Stabni kultura C - preprocesor
« Odpověď #3 kdy: 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.

Logik

  • *****
  • 1 047
    • Zobrazit profil
    • E-mail
Re:Stabni kultura C - preprocesor
« Odpověď #4 kdy: 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ý.


Natix

Re:Stabni kultura C - preprocesor
« Odpověď #5 kdy: 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?

Jarek

Re:Stabni kultura C - preprocesor
« Odpověď #6 kdy: 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 ;).

anonym

Re:Stabni kultura C - preprocesor
« Odpověď #7 kdy: 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

Pavel Tisnovsky

Re:Stabni kultura C - preprocesor
« Odpověď #8 kdy: 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...

Jarek

Re:Stabni kultura C - preprocesor
« Odpověď #9 kdy: 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ě.

Natix

Re:Stabni kultura C - preprocesor
« Odpověď #10 kdy: 06. 04. 2013, 22:03:05 »
Díky. Opět jsem si ověřil, že C není nic pro mě.  ;)

prezek

  • ***
  • 229
    • Zobrazit profil
Re:Stabni kultura C - preprocesor
« Odpověď #11 kdy: 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)
?

Jarek

Re:Stabni kultura C - preprocesor
« Odpověď #12 kdy: 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
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

JS

Re:Stabni kultura C - preprocesor
« Odpověď #13 kdy: 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))