www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik C Programmierung


Autor: Gerhard M. (ggcode)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich hab mal eine grundlegende Frage zu einem Stück C-Quellcode.
Der untere Code soll ein Software-PWM erzeugen.
bool VariableA
char VariableB
char VariableC = 127;

  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
 --VariableB <= VariableC; 

Das ist doch nicht richtig oder?

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

Gruß ggcode

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gerhard M. schrieb:

> Mein C-Compiler löscht aber immer zuerst VariableA und untersucht dann
> erst den Ausdruck
 --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

Autor: Gerhard M. (ggcode)
Datum:

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

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

Gruß Gerhard

Autor: Juergen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> das mit zwischendurch find ich hier nicht in Ordnung.

Ggf kannst du das dem compiler mit volatile sagen.

Autor: Gerhard M. (ggcode)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch ein Zusatz:

VariableA ist ein direkter PortPin eines Mikrocontrollers

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gerhard M. schrieb:
> Hi,
> das mit zwischendurch find ich hier nicht in Ordnung.
>
> Und laut ANSI C ist doch das
=
 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.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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;

Autor: Gerhard M. (ggcode)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Gerhard M. (ggcode)
Datum:

Bewertung
0 lesenswert
nicht 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!!!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.


:-)

Autor: Gerhard M. (ggcode)
Datum:

Bewertung
0 lesenswert
nicht 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.)

Autor: Bernhard R. (barnyhh)
Datum:

Bewertung
0 lesenswert
nicht 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)!

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Gerhard M. (ggcode)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: LSC (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Gerhard M. (ggcode)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
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.

Autor: JL (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Gerhard M. (ggcode)
Datum:

Bewertung
0 lesenswert
nicht 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.

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

   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

Autor: Christian H. (netzwanze) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Gerhard M. (ggcode)
Datum:

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

nee

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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
VariableA = --VariableB <= VariableC;
Das hättest du auch so schreiben können:
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:
VariableB--;
if (VariableB <= VariableC) VariableA = 1;
else                        VariableB = 0;

Autor: Nick Müller (muellernick)
Datum:

Bewertung
0 lesenswert
nicht 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
VariableA = --VariableB <= VariableC;
bei jemanden dem die Sprache geläufig ist als sofort verständlich dazu.
Ähnlich wie ein
for (;;)

Gruß,
Nick

Autor: Gerhard M. (ggcode)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Nick ;-)


Gruß Gerhard

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jungspund (Gast)
Datum:

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

Autor: Nick Müller (muellernick)
Datum:

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

Seufz :-)


Gruß,
Nick

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.