Wie kann man den Wert eines Registers entsorgen, ohne vom Compiler
angemeckert zu werden, die Variable nicht zu nutzen?
uint8_t tmp = REGISTER; //Müll
-> warning: unused variable 'tmp'
Oder den Wert als Rückgabewert einer Fkt. nutzen, aber das kostet.
dummy schrieb:> Wie kann man den Wert eines Registers entsorgen, ohne vom Compiler> angemeckert zu werden, die Variable nicht zu nutzen?>> uint8_t tmp = REGISTER; //Müll
dummy schrieb:> Wie kann man den Wert eines Registers entsorgen, ohne vom Compiler> angemeckert zu werden, die Variable nicht zu nutzen?>> uint8_t tmp = REGISTER; //Müll>> -> warning: unused variable 'tmp'
Klaus schrieb:> Wozu dient in dem Falle der Cast nach void? Bei einem Wer, der> weggeschmissen wird dürfte der Typ doch egal sein, oder?
Zumindest früher war das die Methode der Wahl um anzudeuten, dass mit
einem Ergebnis nichts gemacht wird.
Bei Variablen hab ich das so noch nie gesehen, aber bei Funktionen sah
man das früher öfter um im Code (und dem Compiler) klarzumachen, dass es
Absicht ist, dass der Returnwert einer Funktion ignoriert wird.
Karl heinz Buchegger schrieb:> Zumindest früher war das die Methode der Wahl um anzudeuten, dass mit> einem Ergebnis nichts gemacht wird.
Heute ist es das auch, aber eher um es dem Compiler zu sagen, eben damit
er nicht meckert, weil man ein Statement hinschreibt, das keinen Effekt
hat und dessen Wert man verwirft.
Ich frage mich nur gerade, ob ein einfaches
1
REGISTER;
oder auch dasselbe mit (void) davor tatsächlich einen Lesezugriff auf
das Register verursacht. Bei einem
1
x=REGISTER;
ist klar, daß es gelesen werden muß, genau wie bei einem
1
REGISTER=x;
klar ist, daß es geschrieben wird. Aber wie ist es, wenn man einfach nur
den Namen hinschreibt?
> oder auch dasselbe mit (void) davor tatsächlich einen Lesezugriff auf> das Register verursacht. Bei einem
Kommt drauf an was sich genau hinter REGISTER verbirgt.
Auf einem AVR mit gcc sind die 'Register' ja in Makros nach dem Muster
1
*(volatileuint8_t*)(Adresse);
verpackt. Die Dereferenzierung steht eindeutig da und durch das volatile
kann sich der Compiler auch nicht davor drücken. Ein
1
intmain()
2
{
3
UDR;
4
}
liest definitiv das UDR Register der UART aus und setzt so das Received
Flag zurück.
gsgdhbx schrieb:> Klaert mich doch mal auf - warum will man sowas?>>Wert eines Registers entsorgen
Hauptsächlich weil der Lesevorgang irgendwelche anderen Dinge als
Nebeneffekt triggert. Auf einem AVR musst du zb das UDR Register lesen
um des Received Complete Interrupt Flag zu löschen.
D.h. selbst wenn du innerhalb der entsprechenden ISR das empfangene Byte
gar nicht brauchst, musst du UDR lesen um die Interrupt Anforderung
zurückzusetzen.
Karl heinz Buchegger schrieb:> Auf einem AVR mit gcc sind die 'Register' ja in Makros nach dem Muster>> * (volatile uint8_t*)( Adresse );>> verpackt. Die Dereferenzierung steht eindeutig da und durch das> volatile kann sich der Compiler auch nicht davor drücken.
Aber warum?
Wenn ich den Wert verwende, ist klar, daß das Register dazu gelesen
werden muß, um an diesen ranzukommen.
Wenn ich dem Register was zuweise, ist auch klar, daß ein Schreibzugriff
erfolgen muß, aber kein Lesezugriff.
Wenn ich es inkrementiere, muß beides gemacht werden.
Aber wenn ich mit dem Register gar nichts mache, warum soll dann
ausgerechnet ein Lesezugriff erfolgen?
Oder anders:
> das tun?
Hmm.
Laut C Syntax müsste das eigentlich eine Expression sein, so wie jede
andere auch, die evaluiert wird.
Auch
i = j;
ist ja für den Compiler zuallererst einfach nur eine Expression die
einen Wert liefert. Das innerhalb der Expression eine Zuweisung ist, ist
dann einer der "seltenen" Glücksfälle, dass eine Expression einen
sinnvollen Nebeneffekt hat.
(Allerdings ist das jetzt eine ziemlich aus dem Ärmel geschüttelte
Argumentation. Mal sehen, ob man das mit dem Standard soweit absichern
kann. Kann aber eine Weile dauern, insbesondere dann, wenn ich keinen
downloadbaren C-Standard finde :-)
Darf ichs kurz machen? (Kriege gleich Besuch)
Ich hab mir hier die ANSI-C grammer angesehen
http://www.lysator.liu.se/c/ANSI-C-grammar-y.html
und mich davon überzeugt, das ein einzelner Identifier für eine
Epxression zulässig ist. Auch wenn diese Grammer keinen offiziellen
Status hat, denke ich das man sie akzeptieren kann.
Die Fraghe ist daher, was macht eine Expression
Section 6.5, "Expression"
Clause 1:
An expression is a sequence of operators and operands that specifies
computation of a value, or that designates an object or a function, or
that generates side effects, or that performs a combination thereof.
Aha. Ein Expression 'specifies computation of a value'.
D.h. eine Expression liefert einen Wert. Und da ein Identifer alleine
eine Expression darstellt, liefert diese Expression den Wert des
Identifiers.
Ich weiss, da sind jetzt noch ein paar Lücken, aber mir läuft momentan
die Zeit davon und stöbern im Standard ist zeitaufwändig :-)
Edit: Denkfehler. Wir reden ja nicht von einem Identiefer, sondern von
einem gecasteten Ausdruck der eine Derferenzierung enthält. Aber ich
denke, der Weg durch den Standard ist im wesentlichen identisch. Alles
steht und fällt damit, dass eine Expression einen Wert liefert. Kann man
zeigen, dass ein beliebiger Ausdruck eine Expression ist, hat man auch
gezeigt, dass dies gleichbedeutend ist mit: ein Wert muss geliefert
werden.
Karl heinz Buchegger schrieb:> Section 6.5, "Expression"> Clause 1:> An expression is a sequence of operators and operands that specifies> computation of a value, or that designates an object or a function, or> that generates side effects, or that performs a combination thereof.>> Aha. Ein Expression 'specifies computation of a value'.> D.h. eine Expression liefert einen Wert. Und da ein Identifer alleine> eine Expression darstellt, liefert diese Expression den Wert des> Identifiers.
Ähm, nein, so einfach ist es nicht (dein Ergebnis stimmt zwar, der Weg
dahin aber nicht). Der Knackpunkt ist das "or". Die gegebene Expression
(mit der Dereferenzierung als "äusserstem" Operator) liefert erstmal ein
"lvalue designating the object" (6.5.3.2 Clause 4), damit ist man vom
"specifies computation of a value" in der Fallunterscheidung oben weg.
Als Ergebnis der Dereferenzierung erhalten wir also zunächst mal ein
lvalue. Die Lösung steckt dann in Section 6.3.2.1 ("Lvalues, arrays, and
function designators"), Clause 2:
Except when it is the operand of the sizeof operator, the
unary & operator, the ++ operator, the -- operator, or the
left operand of the . operator or an assignment operator,
an lvalue that does not have array type is converted to the
value stored in the designated object (and is no longer an
lvalue). [...]
Das "an lvalue that does not have array type is converted to the value
stored in the designated object" liefert den gewünschten Lesezugriff.
Die Ausnahmen treffen offensichtlich nicht zu, da das lvalue hier
überhaupt nicht mehr Operand irgendeines Operators ist.
Der muss auch dann erfolgen, wenn das Ergebnis verworfen wird, dank
volatile und Section 6.8.3 ("Expression and null statements"), Clause 2:
The expression in an expression statement is evaluated as a
void expression for its side effects.
in Verbindung mit Section 6.3.2.2 ("void"), Clause 1:
[...] If an expression of any other type is evaluated as
a void expression, its value or designator is discarded.
(A void expression is evaluated for its side effects.)
Andreas
Da hier schon einige Male gefragt wurde, warum man sowas macht. Nachdem
der ADC eingeschaltet wurde musst eine Dummymessung durchgeführt werden,
weil die erste Messung in der Regel mist liefert. Da wäre das schon
recht sinnvoll!
Ich würde schon deshalb ein (void) davorhängen, weil man so auf
ebendiese Besonderheit hingewiesen wird. Möglicherweise erspart man sich
auch einen nett gemeinten Hinweis des Compilers.
Christian L. schrieb:> Da hier schon einige Male gefragt wurde, warum man sowas macht. Nachdem> der ADC eingeschaltet wurde musst eine Dummymessung durchgeführt werden,> weil die erste Messung in der Regel mist liefert. Da wäre das schon> recht sinnvoll!
Für "den" ADC ist das so pauschal nicht richtig. Das muß man genau dann
machen, wenn es so im Datenblatt des entsprechenden ADC's oder
Mikrocontrollers steht.
In diesem Fall würde man das Register allerdings einfach zweimal in die
selbe Variable lesen, und das Problem des TO mit der "unused
variable"-Warnung entstünde gar nicht. Das entsteht nur, wenn man ein
Register einfach nur einmal lesen muß (um damit irgend einen
Seiteneffekt auszulösen), ohne das im weiteren C-Programm mit dem Wert
irgend etwas angefangen wird.
Oliver
eine Frage, ist REGISTER mittels defines definiert, finde ich öfters,
wegen der folgenden C Conformen Notation, weil GNU/sonstwer das
standarisiert, und deshalb von
register int reg;
oder
register reg;
einen
REGISTER reg;
macht weil das portabler ist.
Es könnte aber auch sein, daß der Compiler denkt, REGISTER ist eine
externe int REGISTER(INT, ...) Funktion und er sie so mal anstandslos
Aktzeptiert.
"register" ist mittlerweile meist nur noch ein ignoriertes Relikt aus
Zeiten, in denen der Compiler noch nicht selbst in der Lage war, lokale
Variablen den Prozessorregistern zuzuordnen.