Merkwürdiges Array mit 32-Bit GCC (Linux)

OP #6039909
Lesenswert?

Ausgangssituation:

Aufgabenstellung für Auszubildenden ist Berechnung eines 
Spannungsteilers mit C.

System:   Slackware-Linux 32-Bit
Compiler: GCC 5.3.0
Ausgabe: Console.

Er wollte über Bitmuster in einem Array entscheiden, welche Variable 
eingelesen werden müssen.

Mit folgendem kam er zu mir (und ich hatte mich gefreut dass da 
Engagement vorhanden ist, die letzte printf-Zeile war für ihn zum 
Fehlersuchen):
1
void spgteiler_io(void)
2
{
3
  uint8_t wahl, b, dat;
4
  float   r1,r2, u1,u2, u;
5
  int     ch;
6

7
  /* ---------------------------------------------------
8
     Bitmuster fuer zu lesende Variable
9

10
          Bit|  7   6   5   4   3   2   1   0
11
     zu lesen|              R2  R1  U2  U1  U
12

13
     Beispiel Auswahl 1: U, R1 und U_R1 zu sind lesen,
14
     es muessen somit  Bit 0, Bit1 und Bit3 gesetzt sein
15
     --------------------------------------------------- */
16

17
  //                    1:U,U1,R1     2:U,R1,R2       3:U1,R1,R2
18
  uint8_t rflags[3] = { 0x0b,         0x19,           0x1a };
19

20

21
  while(keypressed()) ch= readkey();                   // Tastenpuffer loeschen
22
  do
23
  {
24
    clrscr();
25
    spgteiler_screen();
26

27
    printf("\n  Gesucht:");
28
    printf("\n  -------------------------\n");
29
    printf("\n            0: Exit\n");
30
    printf("\n            1: R2; U_R2");
31
    printf("\n            2: U_R1; U_R2");
32
    printf("\n            3: U\n");
33
    printf("\n\nEingabe: ");scanf("%d", &wahl);
34

35
    if (!wahl) return;
36
    if (wahl > 3) return;
37

38
    dat= rflags[wahl-1];
39
    printf("\n wahl: %d ; rflags[wahl]: 0x%.2x ; rflags[0]: 0x%.2x", wahl, dat, rflags[0]);

Die Ausgabe der printf-Zeile (bei einer Eingabe 1) ist:
1
Eingabe: 1
2

3
 wahl: 1 ; rflags[wahl]: 0x00 ; rflags[0]: 0x0b

Er (und ich auch) hätte für rflags[wahl] den Wert 0x0b erwartet!

Ändert man das Array rflags nach:
1
  uint8_t rflags[4] = { 0x0b,         0x19,           0x1a };

dann ist die Ausgabe wie erwartet:
1
Eingabe: 1
2

3
 wahl: 1 ; rflags[wahl]: 0x0b ; rflags[0]: 0x0b

!!!!!

Kann das daran liegen, dass diese 3 unsigned Bytes nicht einmal einem 
ganzen Integer (32-Bit = 4 Byte) entspricht und die Adressierung 
irgendwo "klemmt" oder ist das ein reguläres Verhalten und ich übersehe 
etwas.

Wie gesagt, das Problem ist ja gelöst, aber ich wüsste gerne woran das 
liegt.

Wird nach der gleichen Methode eine Auswahl der einzulesenden Variable 
vorgenommen und es existieren bspw. 9 Bytes, dann zeigt ein

uint8_t rflags[9]

nicht das "fehlerhafte" Verhalten von

uint8_t rflags[3]

-----------------------------------------------

Irgendwie mag ich nicht glauben, dass ich einem Fehler von GCC auf die 
Spur gekommen bin und werde mal sehen, wie sich das zum einen auf einem 
64-Bit System und zum anderen mit einer neueren Compilerversion verhält. 
Vielleicht aber hat jemand von Euch eine Erklärung für mich !

Ein schönes Wochenende,

JJ
OP #6039944
Lesenswert?

leo schrieb:
> Ralph S. schrieb:
>> scanf("%d", &wahl);
>
> ASCII '0' .. '9' ist nicht gleich Zahl 0 .. 9.
>
> leo

Das ist Humbug, %d liest eine Zahl und keinen ASCII ein (allerdings - 
und logischerweise - wie wir am Beitrag von foobar sehen, einen 4-Byte 
Wert, der fälschlicherweise einem unsigned char zugeordnet wurde).

foobar schrieb:
> Hier hapert es: uint8_t wahl, ...;
>  ...
>  scanf("%d", &wahl);
>
> Der scanf erwartet einen int-Pointer und schreibt auch ein int (4
> Bytes).

Das hier ist die richtige Antwort (und mir auf den Kopf haue)

Joachim D. schrieb:
> fängt der Index nixht bei 0 an ?

schon, deswegen steht dort ja auch:
1
    dat= rflags[wahl-1];

denn: 1 - 1 = 0

--------------------------------------------------

Vielen Dank an foobar
Moderator #6039968
Lesenswert?

Dirk B. schrieb:
> Da sollte der Compiler aber eine Warnung raus hauen.

Das tut er mit -Wall oder -Wformat auch, sogar sehr ausführlich:

1
test.c:33:37: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘uint8_t *’ {aka ‘unsigned char *’} [-Wformat=]
2
   33 |     printf("\n\nEingabe: ");scanf("%d", &wahl);
3
      |                                    ~^   ~~~~~
4
      |                                     |   |
5
      |                                     |   uint8_t * {aka unsigned char *}
6
      |                                     int *
7
      |                                    %hhd
OP #6040288
Lesenswert?

Smile, die Warnungen hat er auch ausgegeben... allerdings (Asche auf 
mein Haupt) waren die Warnungen weit oberhalb der nachfolgenden 
Compilermeldungen anderer eingebundener Sourcen und nicht zu sehen und 
ich habs bei der Durchsicht auf dem Ausbildungsrechner nicht bemerkt.

Im übrigen gebe ich der Einfachkeit wegen die Programmierübungen auf 
einem Linuxsystem aus und vin daher wird keine .exe erzeugt.

Aaaber, foobar hats gefunden (und der Compiler auch)... und wer lesen 
kann ist klar im Vorteil
#6040642
Lesenswert?

Ralph S. schrieb:
> Ich kenne kein anderes Forum als das hier (egal welches Fachgebiet), wo
> es so extrem pingelig ist wie hier

Aber du hast das doch selbst durch eigene Pingeligkeit angestoßen:

Dirk B. schrieb:
> "Sind ja nur Warnungen. Egal, die EXE hat er ja gemacht."

Ralph S. schrieb:
> Im übrigen gebe ich der Einfachkeit wegen die Programmierübungen auf
> einem Linuxsystem aus und vin daher wird keine .exe erzeugt.

Ob das jetzt eine .exe-Datei ist oder nicht, spielt doch gar keine 
Rolle. Es ging lediglich darum, dass man Warnungen nicht ignorieren 
sollte.
OP #6040970
Lesenswert?

Rolf M. schrieb:
> Ob das jetzt eine .exe-Datei ist oder nicht, spielt doch gar keine
> Rolle. Es ging lediglich darum, dass man Warnungen nicht ignorieren
> sollte.

Warnungen sollte man nie ignorieren, deswegen ja auch "Asche über mein 
Haupt". Zudem war das ja "nur" ein Code bei dem ich den Fehler gesucht 
habe und der nicht von mir war (der mir aber hätte auch passieren 
können).

Schlicht weil in Verbindung mit 8-Bit Controllern eine Variable 
(zumindest bei mir) häufiger uint8_t ist.

Wobei: Selbst auf einem 8-Bit System (jetzt aus dem hohlen Bauch heraus) 
würde ein

scanf("%d", &wahl);

einen Zeiger auf einen 16-Bit Integer zurück liefern.

Schmunzeln muss: Mit "pingelig" meinte ich, was für eine 
Threadverlängerung hier eintritt nachdem die Erklärung bereits geliefert 
worden ist.

Ich arbeite mit einem eigenen Konsoleneditor und bin jetzt am überlegen, 
wie ich eventuell einen Browser für Compilerwarnungen realisieren 
könnte.

Im Moment sieht es so aus, dass es am unteren Bildschirmrand einen 
Ausgabe der Compilermeldungen gibt und, wenn dieses zu klein eingestellt 
ist man nicht sieht, dass es Warnungen gegeben hat. Ich hätte schlicht 
dieses Fenster scrollen sollen und dann wäre mir das wahrscheinlich 
(sagen wir zu 90%) aufgefallen.

Allerdings muß ich auch sagen, dass ich beeindruckt bin, wie schnell 
manche (hier war es foobar) Programmcodes analysieren und das Falsche 
sehen (und ich dachte schon, ich wäre darin gut).

Dass eine Variable den falschen Typ hat habe ich in diesem Fall schlicht 
übersehen (und schlichtweg deshalb, weil ich ansonsten mit eigenen 
Eingaberoutinen und nicht mit scanf arbeite).

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