Guten Morgen,
ich habe gerade ein Brett vorm Kopf. Ich habe eine primitive Funktion,
die aus Debug-Gründen so aussieht:
1
#include<stdint.h>
2
#include<stdio.h>
3
4
int_fast8_tmocksdl_encoder_get_diff(void);
5
6
voidegml_getEncoderIncrement(int*enc)
7
{
8
intdx=mocksdl_encoder_get_diff();
9
10
*enc+=dx;
11
printf("size=%i,%i ",sizeof(*enc),sizeof(enc));
12
printf("dx=%i, enc0 = %i",dx,*enc);
13
//sclamp(enc, 0, egml_action_end-1);
14
printf(" enc1 = %i\n",*enc);
15
}
16
17
18
// Sinngemaess
19
intmain(void)
20
{
21
volatilestruct
22
{
23
intenc;
24
}
25
State;
26
State.enc=0;
27
28
while(1)
29
{
30
egml_getEncoderIncrement(&(State.enc));
31
32
}
33
return0;
34
}
Die Konsolenausgabe sieht so aus:
1
...
2
size=4,8 dx=0, enc0 = 18615 enc1 = 18615
3
size=4,8 dx=0, enc0 = 18615 enc1 = 18615
4
size=4,8 dx=0, enc0 = 18615 enc1 = 18615
5
size=4,8 dx=0, enc0 = 18615 enc1 = 18615
6
size=4,8 dx=255, enc0 = 18870 enc1 = 18870
7
size=4,8 dx=0, enc0 = 18870 enc1 = 18870
8
...
(mocksdl_encoder_get_diff() gibt üblicherweise -1, 0 oder 1 zurück.)
Das Ganze wird mit MinGW unter Windows x64 kompiliert. Der Rückgabewert
dieser Funktion und dx sind vorzeichenbehaftet. printf() hat auch
Parameter für vorzeichenbehaftete Zahlen bekommen. Trotzdem erfolgt die
Zuweisung so, als wäre der Rückgabewert unsigned char.
Im Compiler gibt es natürlich eine Warnung, weil der Struct als volatile
deklariert ist, weil er sonst wegoptimiert würde.
Was passiert hier?
Nachtrag: Wenn ich den Schnipsel in einzeln baue (siehe angehängte
Datei), kann ich den Fehler nicht nachvollziehen. Die
Original-Funktionen so abzuspecken, dass sie sich einzeln bauen lassen,
wird ein Weilchen dauern. Vielleicht fällt dem einen oder anderen aber
trotzdem eine Möglichkeit ein, was mir oben in die Suppe spucken könnte.
Irgend W. schrieb:> ...und wo ist der Beweis dafür das nicht diese Funktion schon die 255> liefert?
Der liegt darin:
1
int_fast8_tmocksdl_encoder_get_diff(void);
und darin, dass unter mingw64 int_fast8_t ein typedef für signed char
ist.
Der kann gar nicht den Wert 255 annehmen.
Das Problem könnte ggf hier liegen:
Walter T. schrieb:> printf("size=%i,%i ", sizeof(*enc), sizeof(enc));
Auf einem 64-Bit-System wird size_t auch 64 Bit breit sein, aber %i
erwartet nur 32 Bit. Da sollte eigentlich auch eine Warnung kommen.
Richtig wäre hier %z.
Rolf M. schrieb:> Das Problem könnte ggf hier liegen:
Wenn man sich die Summe anschaut, wird sie auch als 255 interpretiert.
Nicht nur im printf.
Die Funktion ist kein Geheimnis.
1
/** Differenz des Drehgeber-Standes zwischen aufeinanderfolgenden Aufrufen der
Die Funktion mocksdl_encoder_get() wiederum kann bauartbedingt nur ein
uint_fast8_t zurückgeben, das zwar überläuft, aber pro Aufruf maximal um
einen Wert unterscheidet. Reproduzieren lässt sich das im Original-Build
schon mit diesem Stub:
1
uint_fast8_tmocksdl_encoder_get(void)
2
{
3
staticuint_fast8_ta=0;
4
returna--;
5
}
Bei einem extra-Build der angehängte Datei passiert das nicht. Auch
nicht mit den gleichen Compiler-Optionen:
gcc.exe -O1 -g2 -DMOCKUP_SDL=1 -DDOUBLE_MATH_ENABLED=1
-DGPIO_EMULATION=1 -DUNITTEST_ENABLED=1 -c src_application\debugme.c -o
obj\mockup\src_application\debugme.o -MMD
-IC:\Toolchain\TDM-GCC-64\bin\..\include
-IC:\Toolchain\TDM-GCC-64\bin\..\arm-none-eabi\include
-IC:\Toolchain\TDM-GCC-64\bin\..\arm-none-eabi
Der Fehler liegt also irgendwo außerhalb des hier sichtbaren Codes. Aber
wo? Wo kann ich suchen?
Bei mir kommt da 4 raus, weil fast8 als normales int definiert wird.
Der Überlauf in das Sign Bit bei vorzeichenbehaftetem integern ist in C
undefiniert, da kann einem der Compiler in die Suppe spucken. Sieht man
leider nur im Disassembly.
Walter T. schrieb:> -IC:\Toolchain\TDM-GCC-64\bin\..\arm-none-eabi\include
Ah, deine Zielplattform ist gar nicht mingw. Das ist nur die, wo der
Compiler drauf läuft. Hättest ja auch sagen können, dass du einen
Crosscompiler verwendest, vor allem, wenn du in "PC-Programmierung"
postest, wo man eigentlich vom PC als Zielplattform ausgeht. Wie groß
ist int_least8_t denn dort?
Frank M. schrieb:> Auf jeden Fall gibst Du die unsigned longs mit dem falschen Format %i> aus. Hier solltest Du %lu verwenden. printf("size=%lu,%lu ",> sizeof(*enc), sizeof(enc));
Nein. Wie ich schon schrieb, ist %zu (hatte nur %z geschrieben) das
richtige. sizeof gibt einen size_t zurück, der ein Typedef für unsigned
long sein kann, aber nicht muss. z ist der Größen-Modifier für
size_t. Damit ist es immer richtig.
Rolf M. schrieb:> Ah, deine Zielplattform ist gar nicht mingw. Das ist nur die, wo der> Compiler drauf läuft.
Die Zielplattform ist MinGW, allerdings findet der Build unter EmBitz
statt. Dem kann man nicht abgewöhnen, den entsprechenden Pfad auch
einzubeziehen.
Was wäre, wenn die Deklaration fehlte, und der Compiler einfach auf int
zurückfiele?
a) es müßte eine Warnung ausgegeben werden
b) es würde das obengenannte Phänomen erklären.
Also die Funktionsdeklaration direkt in der Datei (und nicht nur über
den Header) angegeben - Schwupps, kommt das erwartete heraus.
Also hat dieser Hurensohn von Compiler einfach die Warnung in der
Richtung "implizit declaration" oder so verschluckt. So macht das keinen
Spaß. Jetzt muß ich dafür die Ursache suchen.
Walter T. schrieb:> Die Zielplattform ist MinGW, allerdings findet der Build unter EmBitz> statt. Dem kann man nicht abgewöhnen, den entsprechenden Pfad auch> einzubeziehen.
Ah, ok. Dann musst du aber sicherstellen, dass da nicht irgendwelche
Header für die falsche Zielplattform eingebunden werden. Das könnte ja
auch alles komplett durcheinander bringen.
Walter T. schrieb:> Was wäre, wenn die Deklaration fehlte, und der Compiler einfach auf int> zurückfiele?> a) es müßte eine Warnung ausgegeben werden
Kommt drauf an. In C99 oder neuer müsste eine ausgegeben werden. Bei
einer früheren Version wird eine Warnung ausgegeben, wenn die
entsprechende Einstellung (-Wimplicit-function-declaration, Teil von
-Wall) an ist.
> b) es würde das obengenannte Phänomen erklären.
Möglicherweise. Mir würde jedenfalls kein anderer sinnvoller Grund
einfallen, warum für dx0 und dx1 unterschiedliche Werte angezeigt
werden. Was steht denn in dx drin?
> Also die Funktionsdeklaration direkt in der Datei (und nicht nur über> den Header) angegeben - Schwupps, kommt das erwartete heraus.
Ist die Deklaration auch exakt gleich? Wird wirklich der Header
verwendet, von dem du denkst, dass er verwendet wird?
Rolf M. schrieb:> Was steht denn in dx drin?
In dx steht in jedem Fall -1 drin.
Rolf M. schrieb:> wenn die> entsprechende Einstellung (-Wimplicit-function-declaration, Teil von> -Wall) an ist.
Okay, ich habe es gefunden. In EmBitz ist es nicht so einfach, die
Compiler-Aufruf-Zeile zu finden. -Wall und -Wpedantic wurden in der
Umgebung auf meinem einen Rechner nicht richtig durchgereicht. Dafür
finde ich auf dem anderen gerade nicht die Stelle, wo man einstellt, daß
die komplette Build-Zeile im Log steht.
Edit: Für alle, die nach mir suchen (obwohl EmBitz so gut wie tot ist):
Siehe Bild.