Forum: Compiler & IDEs dummy read eines Registers


von dummy (Gast)


Lesenswert?

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.

von Klaus (Gast)


Lesenswert?

Du kannst einfach
1
REGISTER;
schreiben.

Das ist zwar nicht für jeden sofort klar, was da passiert, aber es 
funktioniert.

von Rolf Magnus (Gast)


Lesenswert?

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
1
uint8_t tmp __attribute__((unused)) = REGISTER; //Müll

von dummy (Gast)


Lesenswert?

trés cool! merci!

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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'
1
    (void) REGISTER;

von Klaus (Gast)


Lesenswert?

Wozu dient in dem Falle der Cast nach void? Bei einem Wer, der 
weggeschmissen wird dürfte der Typ doch egal sein, oder?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Rolf Magnus (Gast)


Lesenswert?

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?

von gsgdhbx (Gast)


Lesenswert?

Klaert mich doch mal auf - warum will man sowas?
>Wert eines Registers entsorgen


Gast

von Karl H. (kbuchegg)


Lesenswert?

Rolf Magnus schrieb:

> Ich frage mich nur gerade, ob ein einfaches
>
1
> REGISTER;
2
>
> 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
     * (volatile uint8_t*)( Adresse );
verpackt. Die Dereferenzierung steht eindeutig da und durch das volatile 
kann sich der Compiler auch nicht davor drücken. Ein
1
int main()
2
{
3
   UDR;
4
}
liest definitiv das UDR Register der UART aus und setzt so das Received 
Flag zurück.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Rolf Magnus (Gast)


Lesenswert?

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:
1
      * (volatile uint8_t*)( Adresse ) = 5;
liest das Register auch nicht. Warum sollte ein
1
      * (volatile uint8_t*)( Adresse );
das tun?

von Karl H. (kbuchegg)


Lesenswert?

Rolf Magnus schrieb:

> liest das Register auch nicht. Warum sollte ein
>
1
>       * (volatile uint8_t*)( Adresse );
2
>
> 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 :-)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?


von Karl H. (kbuchegg)


Lesenswert?

Johann L. schrieb:
> sowas?

Merci

von Karl H. (kbuchegg)


Lesenswert?

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.

von Andreas F. (aferber)


Lesenswert?

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

von Chris L. (kingkernel)


Lesenswert?

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!

von (prx) A. K. (prx)


Lesenswert?

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.

von Oliver (Gast)


Lesenswert?

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

von Chris (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

"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.

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.