Forum: Compiler & IDEs Falscher Parameter bei Übergabe an Funktion


von Slowflyer (Gast)


Lesenswert?

Hallo,

ich habe eine Funktion zur Berechnung von Wochentag geschrieben:
1
int8_t dayofweek(int8_t tag, int8_t monat, int8_t jahr){...}

Wenn ich diese zum Testen folgendermaßen aufrufe:
1
var = dayofweek(1,3,5); // 01.03.2005

gibt es Probleme. Im AVR-Stduio wird bei der Simulation der zweite
Parameter nicht korrekt übergeben. Der erste Parameter wird in Register
24, der zweite in r25 und der dritte in r20 übergeben. Der Tag und das
Jahr sind korrekt, der Monat steht aber in r22 und nicht in r25.

Ich verwende den avr-gcc 3.4.4, avr-libc 1.2.5. , die Optimierung -O1
und das AVRStudio 4.12 Build 456 (sonst bekomme ich die Software nicht
mehr in den µC).

Meine Frage nun, ist das ein Bug (Compiler, Studio etc.) oder habe ich
etwas übersehen?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Bitte poste einen Beispielcode.

von Slowflyer (Gast)


Lesenswert?

Hier ein Beispielcode. Hab das mal aus dem Projekt ausgekoppelt und für
den Mega88 kompilert mit den Optimierung -O1. Das Ergebnis ist wie oben
beschrieben.
1
#include <io.h>
2
3
int8_t dayofweek(int8_t tag, int8_t monat,int8_t jahr) 
4
{
5
  static int8_t tage[] = {0,3,3,6,8,11,13,16,19,21,24,26,29};
6
7
  
8
9
  int8_t schaltjahr = 0;
10
  int tage_im_jahr;
11
  int8_t wochentag;
12
13
  tage_im_jahr = tag;
14
  tage_im_jahr += tage[monat-1];
15
  tage_im_jahr += schaltjahr;
16
  wochentag = tage_im_jahr%7;
17
  wochentag += 5; // Doomday 1.1.05 = Samstag
18
  wochentag %= 7;
19
  
20
  return wochentag;
21
}
22
23
int8_t main()
24
{
25
  int8_t var;
26
  var = dayofweek(1,3,5);
27
  var = var-10;
28
  return var;
29
}

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Der generierte Code sieht OK aus.  tag, monat und jahr werden in
r24, r22 und r20 übergeben.  Da jahr nicht ausgewertet wird, wird
der Inhalt von r20 ignoriert, r22 und r24 werden ordnungsgemäß
in interne Register kopiert:

        mov r18,r24
        clr r19
        sbrc r18,7
        com r19

und später von dort benutzt.  Da du sie als int8_t deklariert
hast, wird eine sign extension vorgenommen.

von thkais (Gast)


Lesenswert?

Moin, ich krame mal den Thread heraus, weil ich ein ähnliches Problem
habe.
Ich habe eine Funktion mit den Parametern a,b,c. Rufe ich diese
Funktion auf, werden die Parameter vertauscht - aber nur, wenn ich als
Funktionsparameter das Ergebnis einer anderen Funktion übergebe.
Ich nutze die relativ alte Version 20040720 des Winavr - ist dieser
Fehler durch die Version bedingt und bei einer aktuelleren Version
behoben? Oder mache ich irgendetwas falsch?


test (get_digit(),get_digit(),get_digit());

Gebe ich nun "1", "2", "3" ein, bekomme ich als Ausgabe "3",
"2", "1" - Also genau verdreht.

RS232_wait() wartet auf ein Zeichen von der seriellen Schnittstelle und
gibt es zurück
RS232_send() sendet ein Zeichen
RS232_text() sendet eine Zeichenkette

[code]

uint16_t get_digit (void)
{
  uint8_t text[10];
  uint8_t *pointer;
  uint8_t zeichen;

  pointer = text;

  do
  {
    zeichen = RS232_wait();
    *pointer++ = zeichen;
  }
  while (zeichen != 0x0D);
        *pointer = 0x00;

  return atoi (text);
}

void test (uint16_t a, uint16_t b, uint16_t c)
{
  uint8_t text[10];

  itoa (a,text,10);
  RS232_text(text);
  RS232_send (0x0D);

  itoa (b,text,10);
  RS232_text(text);
  RS232_send (0x0D);

  itoa (c,text,10);
  RS232_text(text);
  RS232_send (0x0D);
}
[\code]

von Karl H. (kbuchegg)


Lesenswert?

> ist dieser
> Fehler durch die Version bedingt und bei einer aktuelleren Version
> behoben? Oder mache ich irgendetwas falsch?
>
>
> test (get_digit(),get_digit(),get_digit());
>
> Gebe ich nun "1", "2", "3" ein, bekomme ich als Ausgabe "3",
> "2", "1" - Also genau verdreht.

Was dieser Code genau macht ist undefiniert.
In C ist die Reihenfolge, in der Argumente ausgewertet
werden nicht definiert.
Du koenntest also  "3", "2", "1" kriegen, oder "2", "1",
"3"
oder "1", "3", "2" oder ....

von thkais (Gast)


Lesenswert?

Danke für die schnelle Antwort, das bringt Licht in die Sache. Ich habe
so etwas ja schon fast vermutet, wäre nicht das erste Mal, dass C
anders reagiert, als ich dachte.
Warum kann C nicht einfach logisch sein und die Parameterliste von
links nach rechts durcharbeiten :(
Wieder einer der Tage, an denen ich die Entscheidung, C zu
programmieren, in Frage stelle ;)

Wieder etwas dazugelernt.
Danke!

von Karl H. (kbuchegg)


Lesenswert?

> Warum kann C nicht einfach logisch sein und die Parameterliste von
> links nach rechts durcharbeiten :(

Weil C als Praemisse hat: Jeder Compilerbauer soll
das Optimium aus der Zielmaschine herausholen koennen.
Und auf den meisten Stack-basierten CPU's ist es nun
mal so, dass die Argumentuebergabe am Stack am schnellsten
geht, wenn man die Argumentliste von rechts nach links
abarbeitet. :-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Wieder einer der Tage, an denen ich die Entscheidung, C zu
> programmieren, in Frage stelle ;)

Warum?  Du kannst doch die Werte allemal in einer Variablen
zwischenspeichern.  Was anderes müsste der Compiler ja auch nicht tun,
wenn er gemäß deiner Logik funktionieren würde -- nur dann müsste er
stets eine solche belegen, während es ihm eben so freigestellt ist,
die effektivste Variante zu suchen.  In den allermeisten Fällen
interessiert einen nämlich die Reihenfolge, in der die Seiteneffekte
für die aktuellen Funktionsparameter evaluiert werden, eher nicht.

Alternativ: lass deine get_digit()-Funktion an Hand eines Parameters
entscheiden, welches Digit sie zurückgeben soll, dann kannst du mit

test (get_digit(1),get_digit(2),get_digit(3));

eine exakte Vorgabe erzielen.

von thkais (Gast)


Lesenswert?

@Jörg: Warum? Weil es solche Fußangeln sind, die einem das Leben schwer
machen. Bei Assembler konnte ich zu 100% davon ausgehen, dass ich
selber Mist gebaut habe, wenn etwas nicht funktionierte. Jetzt muss ich
mit Fehlern leben, bei denen ich nicht sofort die Ursache erkenne... Das
ist m.E. nicht im Sinne eines Programmierers. Aber ich bin nicht
allein:

http://www.math.uni-bremen.de/~thielema/CHater.html

(Aber den Zwinkermann ;) hast Du schon gesehen, gelle?)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Nun, deine URL deutet aber eher darauf hin, dass die Leute
dahinter nach einer höheren Programmiersprache (insbesondere
eine mit automatischer Verwaltung der Objekte) rufen, nicht
nach einer, bei der die Möglichkeit für Fehler ein bis zwei
Größenordnungen mehr sind...

Aber generell: bei einer höheren Programmiersprachen in
irgendeiner Form musst du dich halt mit deren Definition
vertraut machen.  Ada ist sicher auch 'ne gute Alternative,
sieht nicht ganz so kryptisch aus wie C.  Hab's selbst noch
nicht gemacht.

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.