Hallo,
ich hab mal eine grundlegende Frage zu einem Stück C-Quellcode.
Der untere Code soll ein Software-PWM erzeugen.
1
boolVariableA
2
charVariableB
3
charVariableC=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
> 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.
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
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.
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.
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;
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
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!!!
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.
:-)
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.)
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)!
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.
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.
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.
@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
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).
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
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
unsignedcharVariableB;
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.
> 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.
@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
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?
>>> 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:
> 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
>> 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