Forum: Mikrocontroller und Digitale Elektronik Ansi C: define Ausdruck


von entiwckler (Gast)


Lesenswert?

Hallo, in meiner Applikation gibt es folgenden define den ich nicht 
verstehe.
1
#define IS_ETH_PHY_ADDRESS(ADDRESS) ((ADDRESS) <= 0x20)

Die ADDRESS ist niergends im Projekt definiert. Was bedeutet <= 0x20 ?

von Peter II (Gast)


Lesenswert?

entiwckler schrieb:
> Die ADDRESS ist niergends im Projekt definiert. Was bedeutet <= 0x20 ?

das ist zum schluss eine funktion
1
bool IS_ETH_PHY_ADDRESS(ADDRESS int) {
2
   return  ADDRESS <= 0x20;
3
}

von entiwckler (Gast)


Lesenswert?

Vielen Dank.

Was soll dieser Ausdruck
1
 ADDRESS <= 0x20;
 bewirken ?

von Dominik S. (dasd)


Lesenswert?

Das ganze ist die Definition eines Makros.

entiwckler schrieb:
> Was soll dieser Ausdruck ADDRESS <= 0x20; bewirken ?

Naja... wie es da steht "Adresse kleiner oder gleich 20hex".
Raus kommt eben true oder false.

Siehe auch:
http://www2.informatik.uni-halle.de/lehre/c/c_define.html
oder
http://crasseux.com/books/ctutorial/Macro-functions.html

von Dominik S. (dasd)


Lesenswert?

Peter II schrieb:
> das ist zum schluss eine funktion

Naja... es hat nur den selben Effekt wie die von dir aufgeschriebene 
Funktion.
In der Realität werden Makros vom Preprozessor textuell ersetzt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

entiwckler schrieb:
> Die ADDRESS ist niergends im Projekt definiert.

Doch: es ist der formale Parameter des Makros selbst.

Du solltest dir ein gutes Buch über C zulegen und die Grundlagen
lernen.

von entiwckler (Gast)


Lesenswert?

Habs nun vertsnaden. Nochmals Danke!

von na ja (Gast)


Lesenswert?

Aber das ist schon eine komische declaration....
1
bool IS_ETH_PHY_ADDRESS(ADDRESS int) {
2
   return  ADDRESS <= 0x20;
3
}

war nicht vielleicht so ?
1
bool IS_ETH_PHY_ADDRESS(int ADDRESS) {
2
   return  ADDRESS <= 0x20;
3
}

:)

von Dominik S. (dasd)


Lesenswert?

Davon, dass das ein Flüchtigkeitsfehler war bin ich jetzte einfach mal 
ausgegangen :D

Wenn wir schon dabei sind: ^^
1
bool IS_ETH_PHY_ADDRESS(int ADDRESS) {
2
   return  (ADDRESS <= 0x20);
3
}

Des weitern ist bool je nachdem von welchem

> Ansi C

man spricht auch nicht unbedingt so ganz vorgesehen.
Aber lassen wir es gut sein :D

von Karl H. (kbuchegg)


Lesenswert?

Dominik S. schrieb:

> Wenn wir schon dabei sind: ^^
>
>
1
> bool IS_ETH_PHY_ADDRESS(int ADDRESS) {
2
>    return  (ADDRESS <= 0x20);
3
> }
4
>

Nö.
Ist nicht notwendig.
return ist ja kein Funktionsaufruf.
Und die Syntax sagt, dass nach dem Return eine Expression kommt.

Du schreibst ja auch nicht

   i = (5);

also warum sollst du dann

   return (5);

schreiben müssen.

   return 5;

ist fein.

von Dominik S. (dasd)


Lesenswert?

Entschuldige, die Argumentation verstehe ich jetzt nicht ganz und bitte 
um Erklärung :).
1
return 5;

ist ja, wie
1
i = 5;

auch, klar.

"ADDRESS <= 0x20" ist ja aber ein Ausdruck und das Ergebnis des 
Ausdrucks wollen wir zurückgeben.
Folglich schreibe ich
1
return (ADDRESS <= 0x20);

Ich würde ja auch nicht schreiben:
1
i = ADDRESS <= 0x20;

sondern
1
i = (ADDRESS <= 0x20);

---------------------------------------------------------

Ok... gerade mal noch gegoogelt.
Alles was nach return kommt wird IMMER als Ausruck gewertet, ja?

Ich werde wohl trotzdem bei den Klammern bleiben wenn es ein Ausdruck 
ist.
Gewohnheit, gefällt mir besser und selbst der dümmste Compiler kommt 
nicht auf die Idee irgendwann mal nur ADDRESS zu "returnen" :)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Dominik S. schrieb:

> Alles was nach return kommt wird IMMER als Ausruck gewertet, ja?

Richtig, das war in C schon immer so.

> Gewohnheit, gefällt mir besser

Dagegen ist nichts einzuwenden.

> und selbst der dümmste Compiler kommt
> nicht auf die Idee irgendwann mal nur ADDRESS zu "returnen" :)

Wie sollte er auch?  Es steht ja nicht ADDRESS dort.  Falls er
wirklich saublöd wäre und noch nie etwas von der Sprache C gehört
haben sollte, dann könnte er bestenfalls auf die Idee kommen, dass
das ein Syntaxfehler wäre, wenn die Klammern da nicht stehen, aber
nur ADDRESS zurückzugeben geht nicht, denn was sollte dann mit den
restlichen Tokens dieser Zeile passieren?  Ignorieren?

Es ist rein Geschmackssache, ob man da Klammern schreibt.  Ich
selbst mache es nie, aber ich schreibe auch bei
1
#if FOO == 42 && BAR < 13

keine, da ich mir gemerkt habe, dass die Operatorenreihenfolge in
C vorsätzlich so gewählt worden ist, dass das so funktioniert, wie
man es erwarten würde (anders als bei Pascal).

von Karl H. (kbuchegg)


Lesenswert?

Dominik S. schrieb:

> "ADDRESS <= 0x20" ist ja aber ein Ausdruck und das Ergebnis des
> Ausdrucks wollen wir zurückgeben.


Auch 5 ist nichts anderes als ein Ausdruck. Genauso wie i oder i + 5 
oder ...

  return 5;
  return i;
  return i + 5;

> return (ADDRESS <= 0x20);

Auch ADRESSE <= 0x20 ist nichts anderes als ein Ausdruck!
In C gibt es keine Unterscheidung zwischen arithmetischen und logischen 
Ausdrücken. Ausdruck ist Ausdruck. Und der liefert einen Wert.


  j = ( i > 5 ) * 8;

ist perfektes C.
Wir sind halt gewohnt, den 'Ausdruck' in einem if

   if( Bedingung )

als etwas besonderes zu sehen, weil da eine logische Bedingung vorkommt. 
In vielen Programmiersprachen ist das auch so. Aber nicht in C. In C 
lautet die Syntax

   if( Expression )

und der Wert der Expression wird auf 0 bzw. nicht 0 getestet um zu 
entscheiden, welcher der Pfade im if zu nehmen ist. In diesem Sinne ist 
i < 5 in

  if( i < 5 )

einfach nur ein Ausdruck, der mit einem Wert hochkommt, der 0 ist, wenn 
der Vergleich nicht zutrifft und der 1 ist, wenn der Vergleich zutrifft. 
Das if interessiert das < überhaupt nicht. Das if interessiert nur der 
Wert, der sich durch Auswertung des Ausdrucks ergibt - 0 oder nicht 0


> Ich würde ja auch nicht schreiben:
>
>
1
> i = ADDRESS <= 0x20;
2
>

Warum nicht.
Das ist perfektes C.
Wenn es dir lieber ist, da zwecks leichterer Lesbarkeit Klammern zu 
setzen, dann ist dir das natürlich freigestellt. Aber notwendig ist es 
nicht.

> Gewohnheit, gefällt mir besser und selbst der dümmste Compiler kommt
> nicht auf die Idee irgendwann mal nur ADDRESS zu "returnen" :)

Wenn ihm das pssiert, dann hat der Compiler noch ganz andere Probleme 
:-)

von Mark B. (markbrandis)


Lesenswert?

Jörg Wunsch schrieb:
> Es ist rein Geschmackssache, ob man da Klammern schreibt.

Oder aber die Programmierrichtlinien der Firma geben es vor, dass man 
Klammern zu setzen hat.

Ich habe selten C-Code mit zu vielen Klammern gesehen - so manches mal 
aber welchen mit zu wenigen, die der Compiler auch entsprechend 
"verwarnt". ("warning - suggest parentheses around assignment used as 
truth value" und dergleichen)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Mark Brandis schrieb:
> Jörg Wunsch schrieb:
>> Es ist rein Geschmackssache, ob man da Klammern schreibt.
>
> Oder aber die Programmierrichtlinien der Firma geben es vor, dass man
> Klammern zu setzen hat.

Jaja, die Angst-Klammern nach dem Motto "ich bin mir unsicher und dann 
gibt's eben Klammern mit der Gießkanne".

Und wo wir schon dabei sind, natürlich auch Casts mit der Gireßkanne.


Déjà vu... Beitrag "Re: Denke ich zu kompliziert?"

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Und wo wir schon dabei sind, natürlich auch Casts mit der Gireßkanne.

Yep, hatte ich neulich erst wieder.  Und dann hat er sich gewundert,
dass eine zweite Variable überschrieben worden ist, weil er die
Adresse einer short-Variablen in einem scanf() auf "(int *)" gecastet
hat, damit der Compiler nicht mehr meckert ...

von Rolf Magnus (Gast)


Lesenswert?

Mark Brandis schrieb:
> Jörg Wunsch schrieb:
>> Es ist rein Geschmackssache, ob man da Klammern schreibt.
>
> Oder aber die Programmierrichtlinien der Firma geben es vor, dass man
> Klammern zu setzen hat.

Naja, auch dann ist es Geschmackssache. Nur eben nicht deine, sondern 
die von dem, der die Richtlinie geschrieben hat.

> Ich habe selten C-Code mit zu vielen Klammern gesehen - so manches mal
> aber welchen mit zu wenigen, die der Compiler auch entsprechend
> "verwarnt". ("warning - suggest parentheses around assignment used as
> truth value" und dergleichen)

Auch da kann man geteilter Meinung darüber sein, ob die Klammern 
wirklich zu wenig sind und die Warnung wirklich sein müßte.

von Rolf Magnus (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Johann L. schrieb:
>> Und wo wir schon dabei sind, natürlich auch Casts mit der Gireßkanne.
>
> Yep, hatte ich neulich erst wieder.  Und dann hat er sich gewundert,
> dass eine zweite Variable überschrieben worden ist, weil er die
> Adresse einer short-Variablen in einem scanf() auf "(int *)" gecastet
> hat, damit der Compiler nicht mehr meckert ...

Etwas, das ich bei gcc schon immer kontraproduktiv fand, ist bei z.B. 
folgendem Code:
1
void funktion(int* p)
2
{
3
    *p = 3;
4
}
5
6
int main()
7
{
8
    int i;
9
    funktion(i);
10
}

Der gibt folgede Warnung:
1
warning: passing argument 1 of ‘funktion’ makes pointer from integer without a cast

Die stimmt zwar, suggeriert aber, daß ein Cast die Lösung des Problems 
sei, was er - so wie hier - in den meisten Fällen nicht ist.

von W.S. (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> aber ich schreibe auch bei
> #if FOO == 42 && BAR < 13
> keine, da ich mir gemerkt habe, dass die Operatorenreihenfolge in
> C vorsätzlich so gewählt worden ist, dass das so funktioniert, wie
> man es erwarten würde (anders als bei Pascal).

Tja, wenn man zu lange C geübt hat, dann erscheint einem der Rest der 
Welt unlogisch. (Was, ein Geisterfahrer? Nee, hunderte !)

Bedenke bitte, daß Pascal den Typ boolean kennt und logische 
Verknüpfungen streng im jeweiligen Datentyp erfolgen, bei Integer also 
bitweise. Das ist bei C ganz genau so, wenn man z.B. 42 & bar schreibt 
(ohne &&). Nicht Pascal geht falsch, sondern deine Erwartungen sind 
nicht logisch, sondern C-betriebsblind. Wie das? Versuch doch mal
#if FOO == 42 & BAR < 13
zu schreiben, also mit einfachem &.
Das wäre das C Pendant zu if foo=42 and bar<13
Bei Pascal gibt es kein andand oder oror - nun alles klaro?

Ansonsten halte ich deine Schreibweise
#if FOO == 42 && BAR < 13
für grottenschlecht, weil nicht wirklich deutlich lesbar. Man muß zum 
Verstehen immer die Vorrangregeln von C en detail auswendig gepaukt 
dabeihaben - und wehe, man ist noch mit anderen Sprachen befaßt, dann 
ist die Verwechselung vorprogrammiert. Das ist Mist.

Wenn dastünde #if (FOO == 42) && (BAR < 13) dann wäre dies für dich nur 
eine klitzekleine Mühe, aber es erhöht die Lesbarkeit erheblich.

W.S.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

W.S. schrieb:

> Bedenke bitte, daß Pascal den Typ boolean kennt und logische
> Verknüpfungen streng im jeweiligen Datentyp erfolgen, bei Integer also
> bitweise.

Nein, das erklärt das nicht.  Es gibt keinen Grund, warum Pascal
dann nicht bei

  if foo = 42 and bar < 13 then

den Vorrang so geregelt hätte, dass die Vergleiche zuerst passieren.
Schließlich ist die offensichtliche Bedeutung von "and" eine
logische Verknüpfung und nicht eine bitweise.

Das Fehlen eines Boolschen Types im Ur-C bedingt lediglich, dass
man dadurch für bitweises und logisches UND überhaupt erst einmal
zwei verschiedene Operatoren benötigt.

> Ansonsten halte ich deine Schreibweise
> #if FOO == 42 && BAR < 13
> für grottenschlecht, weil nicht wirklich deutlich lesbar.

Ich finde ihn prima lesbar. ;-)

> Wenn dastünde #if (FOO == 42) && (BAR < 13)

...dann fände ich das bereits "obfuscated".  Wo willst du dann
aufhören?  Was ist, wenn da steht:

#if FOO == 42 && BAR < 2 * FOO

Müsste man das dann nicht deiner Meinung nach schreiben:

#if (FOO == 42) && (BAR < (2 * FOO))

weil sich natürlich niemand merken kann, ob der Vergleich oder die
Multiplikation nun Vorrang hat?  Sollte man nicht auch bei
"Punktrechnung geht vor Strichrechnung" "sicherheitshalber" noch
Klammern setzen, denn es könnte ja sein, dass die Programmiersprache
der Wahl das nicht so implementiert hat, wie die Mathematiker es tun
würden?

Dass man zwischen logischem UND und logischem ODER Klammern setzt,
damit man sich deren gegenseitigen Vorrang nicht merken muss, finde
ich OK, aber bei Selbstverständlichkeiten geht schnell die
Übersichtlichkeit verloren.

von Ralph (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> #if (FOO == 42) && (BAR < (2 * FOO))

Diese Klammern müssten so nicht sein wenn
zb.
#define FOO    10

aber bei
zb.
#define FOO    5+3

sieht das schon anders aus

Wenn nur ein Programmierer am Code beteiligt ist, weiß er/sie vielleicht 
bei jedem Define wie es definiert ist.
Sind mehrere am Code beteiligt wird das sehr schnell unübersichtlich.

Und gerade solche define wie zb #define FOO    5+3 könne da ganz schon 
Unordnung stiften.
Von der Seite her ist es sinnvoll die Klammern explizit zu setzen, auch 
wenn es nicht unbedingt notwendig erscheint.
Es vermeidet saublöde Fehler die zum teil sehr schwer zu finden sind.

Das ist der Grund warum es in Firmen oft Regeln gibt, die hier Klammern 
verlangen.
Wenn ich zb unseren Code ansehen, damit sind rund 1/2 MByte Flash des µC 
belegt , da geht es nicht anderes als solche restriktiven Regeln zu 
verwenden.

Und abgesehen davon, es bricht sich niemand einen Zacken aus der Krone 
wenn er an solchen Stellen ein paar Klammern setzt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ralph schrieb:
> Diese Klammern müssten so nicht sein wenn
> zb.
> #define FOO    10
>
> aber bei
> zb.
> #define FOO    5+3
>
> sieht das schon anders aus

Klar.  Deshalb schreibt man auch

#define FOO (5 + 3)

Der Ersteller des Makros weiß nämlich, dass sein Makro unerwünschte
Seiteneffekte haben kann.  Der Benutzer sollte sich darum nicht
kümmern müssen.

von Ralph (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Klar.  Deshalb schreibt man auch
>
> #define FOO (5 + 3)
>
> Der Ersteller des Makros weiß nämlich, dass sein Makro unerwünschte
> Seiteneffekte haben kann.  Der Benutzer sollte sich darum nicht
> kümmern müssen.

Ja klar, aber garantiere das mal wenn 50 und mehr Entwickler die 
Weltweit verteilt sitzen Code zur gesamt Software beisteuern.
Dazu kommt noch autogenerierter Code aus Modellen , oder Codegeneratoren 
für Konfigurationen,.........

Da hilft nur eins, strenge Regeln zur source code Erstellung die auch 
solche Klammerregeln beinhalten.
Ansonsten gibt das ein gewaltiges Chaos.

Dadurch ergibt sich dann auch ein Source Code, der in automatisierten 
Tests auf Code Ebene überprüft werden kann.
Sobald eine Software in irgendwelchen Transportmitteln eine Rolle 
spielt, sind solche Prüfungen auch Pflicht.
Dabei ist es egal ob Auto , Flugzeug,.....

Und ja ich weiß für den Timer einer Kaffemaschine ( auch darin sind 
mittlerweile µC ) brauch man sowas nicht.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ralph schrieb:
> Ja klar, aber garantiere das mal wenn 50 und mehr Entwickler die
> Weltweit verteilt sitzen Code zur gesamt Software beisteuern.

Eben dafür hat man ja die Regeln, die dann besagen, dass nicht
seiteneffektfreie Ersetzungen im Makro geklammert werden müssen.

Bei einem

#if (FOO * 3 < 42)

würden dann auch die "offensichtlichen" Klammern

#if ((FOO * 3) < 42)

nicht mehr helfen, wenn der Trottel, der

#define FOO 5 + 3

gezimmert hat, seine Klammern vergessen hat.

von Rolf Magnus (Gast)


Lesenswert?

Ralph schrieb:
> Jörg Wunsch schrieb:
>> #if (FOO == 42) && (BAR < (2 * FOO))
>
> Diese Klammern müssten so nicht sein wenn
> zb.
> #define FOO    10
>
> aber bei
> zb.
> #define FOO    5+3
>
> sieht das schon anders aus

Nein, auch dann müßten diese Klammern nicht sein, sondern andere. Wenn 
FOO so blöd definiert ist, wird immer noch keine einzige der Klammern in

>> #if (FOO == 42) && (BAR < (2 * FOO))

irgendwas ändern.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ralph schrieb:

> Ja klar, aber garantiere das mal wenn 50 und mehr Entwickler die
> Weltweit verteilt sitzen Code zur gesamt Software beisteuern.
> Dazu kommt noch autogenerierter Code aus Modellen , oder Codegeneratoren
> für Konfigurationen, ...
>
> Da hilft nur eins, strenge Regeln zur source code Erstellung die auch
> solche Klammerregeln beinhalten.

Ja, sinnvolle Coding Rules sind auf jeden Fall notwendig, aber sie 
lösen beiweitem nicht alls Probleme.

> Ansonsten gibt das ein gewaltiges Chaos.

Da helfen z.B. Code-Reviewing und Entwickler und Reviewer, die wissen, 
was sie tun.

Durch technische Regeln und Barrieren wirst du nie das erreichen könne, 
was Erfahrung und kritisches Denken können.

von Mark B. (markbrandis)


Lesenswert?

Johann L. schrieb:
> Durch technische Regeln und Barrieren wirst du nie das erreichen könne,
> was Erfahrung und kritisches Denken können.

Schon. Nur leider ist in vielen Firmen die "wir wollen Entwickler so 
billig wie möglich haben" Mentalität weit verbreitet. Und dann is nix 
mit Erfahrung und kritischer Herangehensweise, dann wird von 
unerfahrenen Leuten im Code herumgesaut dass es nur so kracht.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Mark Brandis schrieb:
> Johann L. schrieb:
>> Durch technische Regeln und Barrieren wirst du nie das erreichen könne,
>> was Erfahrung und kritisches Denken können.
>
> Schon. Nur leider ist in vielen Firmen die "wir wollen Entwickler so
> billig wie möglich haben" Mentalität weit verbreitet. Und dann is nix
> mit Erfahrung und kritischer Herangehensweise, dann wird von
> unerfahrenen Leuten im Code herumgesaut dass es nur so kracht.

"Herumgesaut" ist hier die falsche Vokabel, denn die "Entwickler" können 
und wissen es oft nicht besser, weil sie nicht richtig ausgebildet 
wurden.

Verbockt wird das vom Management.

von Mark B. (markbrandis)


Lesenswert?

Johann L. schrieb:
> Verbockt wird das vom Management.

Gewiss. Weißt Du eine Lösung dafür? :)

von Ralph (Gast)


Lesenswert?

Mark Brandis schrieb:
> Gewiss. Weißt Du eine Lösung dafür? :)

ja klar, Schick all die BWLer nach Hause und setze da Ingenieure hin :-)

von hele (Gast)


Lesenswert?

Manche coding guidelines sind zu recht sehr restriktiv bzgl Makros, das 
sie ein großes Fehlerpotential durch die fehlende Typensicherheit 
bringen und meist problemlos durch konstanten und inline Funktionen 
ersetzt werden können. Man könnte argumentieren, dass mit Makros 
schnellerer Code bei geringerem Optimierungsaufwand durch den Compiler 
entsteht, aber angesichts der Fähigkeiten moderner Compiler und 
Entwicklungswerkzeuge ist das Argument ziemlich zahnlos, um einen 
typenmäßigen blindflug zu rechtfertigen. Die JSF rules (Kampfflugzeug) 
erlauben generell nur Makros für Include Wächter in header files. Das 
heißt nicht, dass ich mich nicht trotzdem immer wieder dazu hinreissen 
lasse.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.