[c] wie wirft man UART-Daten weg?

OP #7395540
Lesenswert?

Guten Morgen,

Zwecks UART-Empfang ohne Interrupt muss man ja nur das RX Ready Flag lesen und dann das RX Datenregister. Ich will nur wissen, /ob/ etwas ankommt, die Daten selbst sind uninteressant. Das Datenregister muss ich aber trotzdem lesen, damit das Flag gelöscht wird. Wie schreibt man das in C am schönsten?

1
int dummy = uart->RDR;

gibt eine Warnung, weil dummy nicht weiter benutzt wird. Statt dummy irgendeine andere Variable nehmen, die an der Stelle zufällig nicht gebraucht wird? Das geht ja wohl garnicht.

1
(void) uart->RDR;

funktioniert angeblich, aber ist das offiziell? Funktioniert das auch mit anderer Optimierung oder einem anderen Compiler?

Persönliche Seite #7395549
Lesenswert?

Bauform B. schrieb:

funktioniert angeblich, aber ist das offiziell? Funktioniert das auch mit anderer Optimierung oder einem anderen Compiler?

Ja. Die Evaluierung eines volatile-Werts darf nicht wegoptimiert werden, selbst wenn der Wert nicht benutzt wird. Das (void) deaktiviert lediglich die Warnung. Das ist zwar nicht garantiert, hat aber keinen negativen Effekt, und es ist kein Beinbruch falls bei irgendeinem Compiler doch eine Warnung kommt.

Peter D. schrieb:

UDR0; UDR0; UDR0;

Ohne das (void) kommt aber wieder die Warnung.

OP #7395699
Lesenswert?

Peter D. schrieb:

Niklas G. schrieb:

Ohne das (void) kommt aber wieder die Warnung.

Welche Warnung, ich bekomme keine.

Dass sich ein anderer Compiler anders verhält, ist doch klar. Bei manchen Dingen darf er das, bei anderen muss er sich an den Standard halten. Die entscheidende Frage ist doch: muss er das Hardware-Register auf jeden Fall lesen? Als Bonusfrage noch: wie schreibt man das so, dass es keine Warnung gibt?

Und die Antwort darauf sieht so aus:

Niklas G. schrieb:

Die Evaluierung eines volatile-Werts darf nicht wegoptimiert werden, selbst wenn der Wert nicht benutzt wird. Das (void) deaktiviert lediglich die Warnung.

Ich finde, das (void) beschreibt auch gut, was da passiert.

es ist kein Beinbruch falls bei irgendeinem Compiler doch eine Warnung kommt.

Naja, ein braves Programm sollte keine Warnungen ausspucken, auch, wenn alle eingeschaltet sind.

Veit D. schrieb:

Wäre dennoch schön gewesen wenn man wüßte um welchen Controller es sich überhaupt handelt.

z.B. STM32F205RET6, STM32L031C4T6, STM32L412KBT6, R5F565N7ADFP... Eigentlich sollte es eine reine C-Frage sein. Natürlich darf man das Flag auch direkt löschen, die Frage ist, was findet ihr verständlicher?

Moderator Persönliche Seite #7395715
Lesenswert?

Bauform B. schrieb:

Ich finde, das (void) beschreibt auch gut, was da passiert.

So ist es. Ein Typecast nach void wird auch an anderen Stellen benutzt um (nicht nur dem Compiler, sondern auch dem geneigten Leser) explizit mitzuteilen: "Da gibt es einen Wert, aber der wird weggeschmissen."

Insofern wäre ein Compiler auch schlecht beraten, für genau diesen Fall trotzdem noch eine Warnung zu generieren.

Moderator Persönliche Seite #7395739
Lesenswert?

Jörg W. schrieb:

So ist es. Ein Typecast nach void wird auch an anderen Stellen benutzt um (nicht nur dem Compiler, sondern auch dem geneigten Leser) explizit mitzuteilen: "Da gibt es einen Wert, aber der wird weggeschmissen."

ACK.

Insofern wäre ein Compiler auch schlecht beraten, für genau diesen Fall trotzdem noch eine Warnung zu generieren.

Ich kenne keinen. Ganz im Gegenteil: Durch das (void) davor kann man oft die Warnung verhindern. Die StdPeripheral-Lib für die STM32 hat zum Beispiel an einigen Stellen die Macke, dass sie einen Funktionsparameter zwar in der Parameter-Liste aufführen, diesen dann aber gar nicht in der Funktion selbst nutzen. Bei eingeschalteten Warnungen (-Wextra) meckert der Compiler (gcc) dann: "error: unused parameter ‘param3’ [-Werror=unused-parameter]"

Abhilfe schafft dann ein einfaches:

1
(void) param3;

direkt als erstes Statement innerhalb der Funktion.

Ohne das (void) davor erhält man übrigens dann die Warnung: "warning: statement with no effect [-Wunused-value]"

#7395761
Lesenswert?

Bauform B. schrieb:

Veit D. schrieb:

Wäre dennoch schön gewesen wenn man wüßte um welchen Controller es sich überhaupt handelt.

z.B. STM32F205RET6, STM32L031C4T6, STM32L412KBT6, R5F565N7ADFP... Eigentlich sollte es eine reine C-Frage sein. Natürlich darf man das Flag auch direkt löschen, die Frage ist, was findet ihr verständlicher?

Wenn man das Flag bei den STM selbst löschen kann, dann bleibt das eine reine Geschmacksfrage. Kommentieren sollte man die Zeile sowieso warum man das macht. Ich würde das Flag direkt löschen, weil das bestimmt auch schneller ist.

OP #7395866
Lesenswert?

Frank M. schrieb:

Jörg W. schrieb:

Ab C23

Sehr schick! Und auch sinnvoll.

Am 1. April gab's den letzten Draft, da steht es drin, zwar in Klammern und mit nur zwei Worten im Nebensatz, aber immerhin.

1
6.9.1 Function definitions
2

3
7 The declarator in a function definition specifies the name of the
4
  function being defined and the types (and optionally the names)
5
  of all the parameters;
6

7
9 Each parameter has automatic storage duration; its identifier,
8
  if any, is an lvalue.

Aber es wird wohl ein C24 draus...

1
Revised C23 Schedule WG 14 N 2984
2

3
Start      Event                           Days  Completed
4
2023-02-13 Editor readies document for DIS    7  2023-02-20
5
2023-02-20 ISO editing (submit DIS ballot)   56  2023-04-17
6
2023-04-17 DIS ballot                       182  2023-10-16
7
2023-10-16 Contingency                       14  2023-10-30
8
2023-10-30 Editor prepares IS                14  2023-11-13

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf

#7396287
Lesenswert?

Jörg W. schrieb:

int foo(int something, char /* no name here */) { // ... }

Jörg W. schrieb:

Wilhelm M. schrieb:

Einfach C++ benutzen ;-) Da geht das!

Wundert nun nicht so sehr, beide Standards versuchen ja schon, möglichst viel synchron zu halten.

War mir gar nicht bewusst, daß C das nicht kennt. gcc compiliert das ab gcc 11, lustigerweise sogar mit -std=c90.

Oliver

Moderator Persönliche Seite #7396444
Lesenswert?

Veit D. schrieb:

sollte das für C und C++ nicht eher

maybe unused

sein?

Vielleicht auch das :), wie ich schon schrieb, ich habe da lange nicht mehr rein geschaut. Ich hatte mir nur gemerkt, dass es überhaupt ein Attribut dafür gibt.

Das hat natürlich dann den Vorteil (auch gegenüber dem unbenannten Parameter), dass man sowas machen kann:

1
int foo(int something, int debugchannel [[maybe_unused]]) {
2
#ifdef DEBUG
3
  fprintf(debugchannel, "Entering foo(%d) ...\n", something);
4
#endif
5
  // blablah
6
  return 42;
7
}

Ohne das "maybe" könnte der Compiler sich ja beschweren, dass es bei DEBUG dann doch benutzt wird.

OP #7396511
Lesenswert?

Veit D. schrieb:

immer wieder 42. :-) :-)

1
uint16_t  config[cf_cf_size] = {
2
   [ cf_contrast   ] = 42,   // %
3
   [ cf_brightness ] = 17,   // %
4
   [ cf_timeout    ] = 42,   // * 10s
5
   [ cf_volume     ] = 42,   // %
6
   [ cf_note       ] = 42,
7
   [ cf_len        ] = 17,   // * 10ms
8
   [ cf_baud       ] = 4800,
9
};

Das sind die optimalen Einstellungen für das LCD. Im Ernst, die sind echt, also ausprobiert und dann hier als Default eingetragen. Am besten ist cf_note, die Tonhöhe trifft genau die Resonanz vom Beeper :)

Moderator Persönliche Seite #7396931
Lesenswert?

Peter D. schrieb:

Der reine Lesezugriff bleibt ohne Warnung.

-Wextra eingeschaltet?

Da ist wohl der AVR-GCC etwas intelligenter bzw. weniger besserwisserisch.

Hat wohl eher damit zu tun, dass UDR0 als volatile deklariert ist. Das Lesen eines volatile-Registers ohne Zuweisung ist auf jeden Fall sinnvoller als das Lesen einer Variablen ohne anschließende Zuweisung. Mach das mal mit einer Variablen, dann wirst Du auch beim AVR-gcc die Warnung (Voraussetzung: -Wextra) sehen.

Ich kann mir auch nicht vorstellen, dass ein gcc für einen STM32 dümmer ist als für einen AVR, s.a. Beitrag "Re: [c] wie wirft man UART-Daten weg?"

#7397049
Lesenswert?

Frank M. schrieb:

Hat wohl eher damit zu tun, dass UDR0 als volatile deklariert ist. Das Lesen eines volatile-Registers ohne Zuweisung ist auf jeden Fall sinnvoller als das Lesen einer Variablen ohne anschließende Zuweisung. Mach das mal mit einer Variablen, dann wirst Du auch beim AVR-gcc die Warnung (Voraussetzung: -Wextra) sehen.

Die Option -Wall beinhaltet auch -Wunused-value. Damit bekommt man eine Warnung, wenn man einen Ausdruck hat, dessen Ergebnis nicht verwendet wird (siehe: UDR + 1), was ein rvalue ist.

In UDR steckt ja der Indirektionsoperator / Zeigerdereferenzierungsoperator (*) drin, das Ergebnis ist ein volatile-lvalue. Wegen der volatile-Qualifizierung ist dem Compiler klar, dass hier nicht nur ein Wert bestimmt werden soll, sondern dass auch ein Seiteneffekt erzeugt werden soll. volatile bedeutet ja, dass es sich um eine "besondere Speicherzelle" handelt, für die die üblichen Annahmen, die Optimierungen ermöglichen, nicht gelten. Daher keine Warnung.

Ich kann mir auch nicht vorstellen, dass ein gcc für einen STM32 dümmer ist als für einen AVR, s.a.

Ist es auch nicht, da es eine Frontend-Warnung ist, und das ist für gcc und avr-gcc natürlich identisch.

Moderator Persönliche Seite #7397189
Lesenswert?

Wilhelm M. schrieb:

Die Option -Wall beinhaltet auch -Wunused-value.

Korrekt, danke für die Richtigstellung. Aber -Wall enthält unverständlicherweise nicht -Wunused-parameter, auf welches sich mein Beispiel für STM32 bezog. Hier benötigt man -Wextra.

1
$ cat a.c
2
#include <stdio.h>
3

4
void
5
foo (int x, int y)
6
{
7
    x;
8
}
9

10
int
11
main ()
12
{
13
    foo (3, 4);
14
    return 0;
15
}
16

17
$ cc -O -Wall a.c
18
a.c: In function ‘foo’:
19
a.c:6:5: warning: statement with no effect [-Wunused-value]
20
     x;
21
     ^
22

23
$ cc -O -Wall -Wextra a.c
24
a.c: In function ‘foo’:
25
a.c:6:5: warning: statement with no effect [-Wunused-value]
26
     x;
27
     ^
28
a.c:4:17: warning: unused parameter ‘y’ [-Wunused-parameter]
29
 foo (int x, int y)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren