Forum: Mikrocontroller und Digitale Elektronik C Programmierung


von Gerhard M. (ggcode)


Lesenswert?

Hallo,
ich hab mal eine grundlegende Frage zu einem Stück C-Quellcode.
Der untere Code soll ein Software-PWM erzeugen.
1
bool VariableA
2
char VariableB
3
char VariableC = 127;
4
5
  VariableA = --VariableB <= VariableC;

Meine Denkweise ist so:

VariableC wird mit VariableB verglichen, und der boolsche Wert in 
VariableA geschrieben.

Mein C-Compiler löscht aber immer zuerst VariableA und untersucht dann 
erst den Ausdruck
1
 --VariableB <= VariableC;

Das ist doch nicht richtig oder?

Vielen Dank schonmal für ne sinnvolle Erklärung.

Gruß ggcode

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Mein C-Compiler löscht aber immer zuerst VariableA und untersucht dann
> erst den Ausdruck
Der Compiler darf zwischendurch machen, was er will.
Nur hinterher muß das Ergebnis passen.

von Stefan E. (sternst)


Lesenswert?

Gerhard M. schrieb:

> Mein C-Compiler löscht aber immer zuerst VariableA und untersucht dann
> erst den Ausdruck
1
 --VariableB <= VariableC;
>
> Das ist doch nicht richtig oder?

Warum nicht?
Der erzeuge Assembler-Code folgt wahrscheinlich dieser Logik:

VariableA = 0
Werte Vergleich aus
wenn Ergebnis true
  dann VariableA = 1

von Gerhard M. (ggcode)


Lesenswert?

Hi,
das mit zwischendurch find ich hier nicht in Ordnung.

Und laut ANSI C ist doch das
1
=
 ein RWert, dann heißt das doch ich arbeite den Ausdruck von rechts nach 
links ab.
Zuerst vergleichen und dann zuweisen

Gruß Gerhard

von Juergen (Gast)


Lesenswert?

> das mit zwischendurch find ich hier nicht in Ordnung.

Ggf kannst du das dem compiler mit volatile sagen.

von Gerhard M. (ggcode)


Lesenswert?

Noch ein Zusatz:

VariableA ist ein direkter PortPin eines Mikrocontrollers

von Karl H. (kbuchegg)


Lesenswert?

Gerhard M. schrieb:
> Hi,
> das mit zwischendurch find ich hier nicht in Ordnung.
>
> Und laut ANSI C ist doch das
1
=
 ein RWert, dann heißt das doch ich
> arbeite den Ausdruck von rechts nach links ab.
> Zuerst vergleichen und dann zuweisen

Nö.

Die einzige Vorschrift die für den Compiler gilt lautet:
  Wenn im logischen Ablauf der ; erreicht ist (der sog. Sequence Point)
  müssen alle Aktionen und Nebeneffekte abgeschlossen sein.

Wie sich der Compiler die Arbeit aufteilt ist seine Sache.

von Stefan E. (sternst)


Lesenswert?

Gerhard M. schrieb:

> das mit zwischendurch find ich hier nicht in Ordnung.

Um was genau geht es dir überhaupt?
Entscheidend ist doch, dass hinterher in VariableA das korrekte Ergebnis 
steht. Wie der Compiler das macht, kann dir doch wurscht sein. Und falls 
es darum geht, dass in VariableA etwas anderes steht, als du erwartest 
hast, könnte der richtige Code hilfreich sein.

von Karl H. (kbuchegg)


Lesenswert?

Gerhard M. schrieb:
> Noch ein Zusatz:
>
> VariableA ist ein direkter PortPin eines Mikrocontrollers

Das hättest du zwar etwas früher sagen sollen, da es an manchen Stellen 
einen Unterschied macht. Allerdings nicht im gegenständlichen Fall. Da 
ändert es nichts.

Wahrscheinlich ist dein Problem, dass zwischendurch eine 0 am Portpin 
auftaucht, die da eigentlich nicht sein sollte.

Manchmal ist es nicht klug zu clever zu sein :-)

  if( --VariableB <= VariableC )
    VariableA = true;
  else
    VariableA = false;


es könnte auch gehen:
  VariableA = ( --VariableB <= VariableC ) ? true : false;

von Gerhard M. (ggcode)


Lesenswert?

Hi,
ja das war mein Fehler stimmt. Genau das passiert, das am Ausgang kurz 
ne 0 erscheint.

 > if( --VariableB <= VariableC )
 >   VariableA = true;
 > else
 >   VariableA = false;

genau so hab ich das dann auch umgeschrieben, ich wollte nur verstehen 
wieso der erste Ausdruck nicht funktioniert.

PS: Der erste Ausdruck hat jetzt jahrelang funktioniert bis zu einem 
Compilerupdate und dann ging die Sucherei los ......

Gruß Gerhard

von Gerhard M. (ggcode)


Lesenswert?

Hallo,
da steht ja ne logische Erklärung

>Die einzige Vorschrift die für den Compiler gilt lautet:
>  Wenn im logischen Ablauf der ; erreicht ist (der sog. Sequence Point)
>  müssen alle Aktionen und Nebeneffekte abgeschlossen sein.

>Wie sich der Compiler die Arbeit aufteilt ist seine Sache.

hätte ich fast übersehen.

Danke!!!

von Karl H. (kbuchegg)


Lesenswert?

Gerhard M. schrieb:

> PS: Der erste Ausdruck hat jetzt jahrelang funktioniert bis zu einem
> Compilerupdate und dann ging die Sucherei los ......

Du schreibst jetzt 100 mal:
  Ich soll keine Annahmen darüber treffen, in welcher Reihenfolge der
  Compiler welche Auswertungen macht. Wenn die Reihenfolge wichtig ist,
  dann lautet die Lösung immer explizit zu sein.


:-)

von Gerhard M. (ggcode)


Lesenswert?

Zum Glück hab ich nicht die Annahme getroffen ;-)
sondern mich nur gewundert, wieso er das so compilert.

Dann aber behauptet das es das nicht so machen darf ....

:-((

Gruß Gerhard

Ergebnis = 100 * (Ich soll keine Annahmen darüber treffen, in welcher 
Reihenfolge der
  Compiler welche Auswertungen macht. Wenn die Reihenfolge wichtig ist,
  dann lautet die Lösung immer explizit zu sein.)

von Bernhard R. (barnyhh)


Lesenswert?

Ich beziehe mich auf den Original-Post und lasse den Rest zwischendrin 
weg.
Mach die Variablen mal bitte volatile. Dann tut das Ding auch!

Mit dem Wörtchen "volatile" sagt der Programmierer dem Compiler: "Lieber 
Compiler, diese Variable verhält sich anders als Du zu denken glaubst! 
Ich, der Programmierer, Dein Herr und Gebieter, weiß im Gegensatz zu 
Dir, was die Hardware an dieser Stelle tut."

Und jetzt schreibe bitte - auch mindestens 100 mal -
"Ich soll dem Compiler Bescheid sagen, welches Stück Hardware anders 
arbeitet als der Compiler-Bauer vorhergesehen hat!"

Bernhard

BTW:
Willkommen im Club (der volatile-geschädigten)!

von Klaus (Gast)


Lesenswert?

Das 2. Gebot lautet:

Du sollst sprechende Namen verwenden.

Du sollst nicht eine Portdefinition als "Variable" bezeichnen.
Portdefinitionen sind i.d.R. vom Compilerhersteller in einer .H Datei 
mitgeliefert (für jeden uC Typ) und von Haus aus "volatile".


Ein weiteres Gebot sagt:

Du sollst nicht komplizierte Codezeilen schreiben.


In diesem Sinn ist ...
VariableA = --VariableB <= VariableC;
... ziemlicher Mist.

von (prx) A. K. (prx)


Lesenswert?

Gerhard M. schrieb:

> VariableA ist ein direkter PortPin eines Mikrocontrollers

Der hoffentlich volatile ist. Wenn er es ist, dann ist andererseits 
Stefans Schema, erst zu löschen und dann bedingt zu setzen, nicht 
zulässig.

Wahrscheinlich hast du also aus dem Verhalten des Compilers bei einer 
normalen Variable auf das Verhalten bei einer volatilen Variable (Port) 
geschlossen. Und das ist nicht korrekt.

Ergo: Dein Code mag für manche ungewöhnlich aussehen, sollte aber bei 
einem korrekten Compiler und korrekter Deklaration des Portpins auch wie 
vorgesehen funktionieren.

von (prx) A. K. (prx)


Lesenswert?

Karl heinz Buchegger schrieb:

>   if( --VariableB <= VariableC )
>     VariableA = true;
>   else
>     VariableA = false;
>
> es könnte auch gehen:
>   VariableA = ( --VariableB <= VariableC ) ? true : false;

Wobei GCC ohne volatile die Neigung besitzt, solcher Intention zuwider 
zu handeln, weil er die 3 präsentierten Varianten u.U. als völlig 
äquivalent erkennt und das macht was er für optimal hält.

von Gerhard M. (ggcode)


Lesenswert?

@KlausDas 2.
>Gebot lautet:

>Du sollst sprechende Namen verwenden.

Klaus, das ist schon klar. In meinem Code werd ich die Namen so nicht 
verwenden, das ist schon ersichtlich was ein Portpin ist und was die 
Variablen für einen Wertebereich und Funktion haben .....

Sollte ja nur als Beispiel gelten :-)

Gruß Gerhard

von LSC (Gast)


Lesenswert?

Hallo Gerhard,

Änderst du VariableC eigentlich nochmal?
Wenn sie nämlich immer auf 127 (Maximalwert von char) stehen bleibt 
wundert es mich, dass der Compiler den Vergleich nicht gleich eliminiert 
(da VariableA immer True).

von Gerhard M. (ggcode)


Lesenswert?

Hallo,
die Variable 'char' sind bei meinem Compiler 'unsigned' also von 0-255.

Das heißt VariableB wird Rückwärts gezählt, und wird bei 0 wieder auf 
255 gesetzt.

Somit hast du in der VariableC dein PWM-Verhältnis --> 127 = 50%

Gruß Gerhard

von Karl H. (kbuchegg)


Lesenswert?

Gerhard M. schrieb:
> Hallo,
> die Variable 'char' sind bei meinem Compiler 'unsigned' also von 0-255.
>

das solltest du niemals als gegeben voraussetzen!

Wenn es für dein Programm wichtig ist, dass du mit unsigned char 
arbeitest, dann benutze immer
1
unsigned char VariableB;

sei also explizit!

Einen normalen 'char' benutzt man nur dann, wenn man tatsächlich 
Character im Sinne von Text da drinn speichert, es also egal ist, ob die 
Defaulteinstellung des Compilers signed oder unsigned ist. Wenn du einen 
char als Speicher für Zahlen im Sinne eines Bytes benutzt, dann nimm 
immer entweder 'signed char' oder 'unsigned char' und nagle den Compiler 
damit auf die dir genehme Version fest.

von JL (Gast)


Lesenswert?

> VariableA = --VariableB <= VariableC;

wer macht denn sowas Krankes nur um sich ein paar byte Quellcode zu 
sparen? Code sollte verständlich sein und auch von einem 
Aussenstehenden/Nachfolger lesbar sein.Hab schon genügend gesehen, was 
später einfach weggeworfen wurde und neugeschrieben weils keiner mehr 
vernünftig/effizient warten konnte.

Aber das war ja nicht die Frage.

von Gerhard M. (ggcode)


Lesenswert?

@jl
Das mag vieleicht krank sein, wenn du aber ein Controller hast der mit 
100% seiner Speichergrösse belegt ist, und du hast keine Chance den 
Controller gegen einen anderen zu tauschen was machst du dann?

Ich geb dir Recht, Code sollte verständlich sein und lesbar.
Aber lesbar ist das schon.

So wäre es schöner ganz klar.

1
  if( VariableB <= VariableC )
2
    VariableA = true;
3
   else
4
    VariableA = false;
5
6
   VariableB--;

Doch hat da mein Compiler in einer früheren Version ungefähr 25 
Anweisungen erzeugt, und im anderen Fall nur 10 ....

Der Code läuft in der main() und sollte ein PWM erzeuegen, mit maximal 
möglicher Frequenz.

@Karl heinz Buchegger

Ich nutze in meinem Compiler int8 :-)

unsigned char = int8 = char ....

Ist in diesem Compiler per Default so.

PS: PIC16F676 und CCS-Compiler

Gruß Gerhard

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Gerhard M. schrieb:
> Doch hat da mein Compiler in einer früheren Version ungefähr 25
> Anweisungen erzeugt, und im anderen Fall nur 10 ....
Dabei hattest Du natürlich alle Optimierungen abgeschaltet, oder?

von Gerhard M. (ggcode)


Lesenswert?

Christian H. schrieb:
> Gerhard M. schrieb:
...
> Dabei hattest Du natürlich alle Optimierungen abgeschaltet, oder?

nee

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

>>> VariableA = --VariableB <= VariableC;
>>wer macht denn sowas Krankes
> Das mag vieleicht krank sein, wenn du aber ein Controller hast der mit
> 100% seiner Speichergrösse belegt ist, und du hast keine Chance den
> Controller gegen einen anderen zu tauschen was machst du dann?
Ja, und schreib bloß keine Kommentare rein, die brauchen auch 
Rechenzeit. Das gilt z.B. für Basic-Interpreter...

Kompakter Quellcode bedeutet nicht unbedingt kompakter Maschinencode :-o
1
VariableA = --VariableB <= VariableC;
Das hättest du auch so schreiben können:
1
VariableA=VariableC>--VariableB?1:0;
Das ist sogar kürezer, und der Kopierschutz ist implizit mit eingebaut 
;-)

Diese Zeilen sind im Maschinencode genauso kompakt, aber besser lesbar:
1
VariableB--;
2
if (VariableB <= VariableC) VariableA = 1;
3
else                        VariableB = 0;

von Nick M. (Gast)


Lesenswert?

> Diese Zeilen sind im Maschinencode genauso kompakt, aber besser lesbar:

Naja, man weiß nie was der Compiler draus macht.

Und von wegen besser lesbar: Es gibt in jeder Sprache (auch 
Programmiersprachen) sogenannte "Idioms". Und da zählt
1
VariableA = --VariableB <= VariableC;
bei jemanden dem die Sprache geläufig ist als sofort verständlich dazu.
Ähnlich wie ein
1
for (;;)

Gruß,
Nick

von Gerhard M. (ggcode)


Lesenswert?

Danke Nick ;-)


Gruß Gerhard

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

>> Doch hat da mein Compiler in einer früheren Version ungefähr 25
>> Anweisungen erzeugt, und im anderen Fall nur 10 ....
Der Code dort im Beitrag "Re: C Programmierung"
ist ein anderer als der im 
Beitrag "C Programmierung"
Kein Wunder eigentlich, dass der Compiler was anderes daraus macht  :-o

von Jungspund (Gast)


Lesenswert?

> Naja, man weiß nie was der Compiler draus macht.
Natürlich weiß man das. gcc -S

von Nick M. (Gast)


Lesenswert?

Jungspund schrieb:
>> Naja, man weiß nie was der Compiler draus macht.
> Natürlich weiß man das. gcc -S

Seufz :-)


Gruß,
Nick

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.