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

OP #6039909
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
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
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
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
Ralph S. schrieb:
> daher wird keine .exe erzeugt.

Das EXE ist als Kurzform für Executable gemeint.

DOS (und auch Windows) benötigen das .exe als Dateinamenerweiterung.

 *ix Systeme benötigen diese Kennzeichnung nicht. Dennoch bleibt es eine 
EXE ?


Wird am Ende keine Erfolgsmeldung (1 Warnung, 0 Fehler) mehr ausgegeben?
Dirk B. schrieb:
> *ix Systeme benötigen diese Kennzeichnung nicht. Dennoch bleibt es eine
> EXE ?

das stand aber im Kontext zu "... die 'EXE' hat er(der gcc) ja 
gemacht..." -
und das ist zumindest missverständlich, denn executables entstehen durch 
das das setzen des X-Bits ... und sind keine Aufgaben des `Compilers 
oder Linkers
Walter K. schrieb:
> und das ist zumindest missverständlich, denn executables entstehen durch
> das das setzen des X-Bits ...

Das gibt nur das Recht zur Ausführung.
Kann ich einem Bild (jpg) auch geben, bringt aber nichts.

> ... und sind keine Aufgaben des `Compilers
> oder Linkers

Die machen die technische Seite (für Binaries)
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
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

Eine eigene Frage? Dieser Thread ist über 6 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.