WinAPI Datentyp Inkompatiblität mit gcc 3.4.2
-
Hallo zusammen,
Ich habe ein Problem im Zusammenspiel von WinAPI mit gcc Version 3.4.2 unter Windows XP.
Gleich vorweg: Ich kann den Compiler weder wechseln noch updaten, keine Makefileänderung durchführen und auch keine anderen Konfigurationen ändern.Ich arbeite an zwei C-Funktionen in einer Software Komponente einer Simulation, in die ich Funktionalität einbaue und die dann mit einem ansonsten existierenden Projekt mit oben beschriebenen System zusammencompiliert/-gelinkt werden.
An mehreren Stellen rufe ich die Funktionen
QueryPerformanceCounterhttp://msdn.microsoft.com/en-us/library/ms644904%28VS.85%29.aspx
undQueryPerformanceFrequencyhttp://msdn.microsoft.com/en-us/library/ms644905%28VS.85%29.aspx
auf.Diese haben einen out Parameter vom Typ LARGE_INTEGER*, der laut MSDN wie folgt definiert ist:
typedef union _LARGE_INTEGER { struct { DWORD LowPart; LONG HighPart; } ; struct { DWORD LowPart; LONG HighPart; } u; LONGLONG QuadPart; } LARGE_INTEGER, *PLARGE_INTEGER;mein eigentlicher Ansatz war einfach, die Methoden wie folgt aufzurufen:
LARGE_INTEGER value; QueryPerformanceCounter(&value);Leider wird der Code nicht compiliert mit der "aussagekräftigen" Fehlermeldung:
Syntax error before valuein der Zeile mit der Variablendefinition.
Ich habe dann nach langem Suchen mal versucht, mir den Typ per typedef neu zu definieren:
typedef union _L_I { struct { DWORD LowPart; LONG HighPart; } ; struct { DWORD LowPart; LONG HighPart; } u; LONGLONG QuadPart; } L_I, *PL_I; L_I value;Das compiliert auch nicht, und zwar bemängelt er dann einen
Syntax error before DWORD(bezogen auf "DWORD LowPart;")
Ich schätze daher, dass der Compiler mit anonymen structs in unions nicht klarkommt. (Diverse Treffer bei Google erhärten den Verdacht, aber können ihn nicht festklopfen)Meine erste Frage:
Sind meine Schlussfolgerungen bis hierher richtig oder habe ich hier etwas nicht beachtet / übersehen / falsch gedacht?Ich habe dann mehrere Sachen ausprobiert, um ein Workaround zu basteln (die Funktion QueryPerformanceCounter ist ja implementiert und wenn ich ihr nur genug Speicher gebe, müsste das klappen, so meine Logik - bitte korrigieren, falls falsch gedacht) und folgender Code compiliert schon mal:
void* value = malloc(8); // 8 Byte (8 = sizeof(LARGE_INTEGER), da 64 Bit INT) QueryPerformanceCounter(value); // ... free(value);Allerdings stürzt mir die Software ab, wenn ich value nach dem Aufruf von QueryPerformanceCounter versuche in einen Pointer auf ein 8 Byte Integer (long long
zu casten und dann zu dereferenzierenvoid* value = malloc(8); // 8 Byte (8 = sizeof(LARGE_INTEGER), da 64 Bit INT) QueryPerformanceCounter(value); *((long long*)value) ; // BOOOM! free(value);Wenn ich den Speicher von value vorher in einen (long long*) caste, stürzt bereits der Auruf von QueryPerformanceCounter ab.
void* value = (long long*)malloc(8); // 8 Byte (8 = sizeof(LARGE_INTEGER), da 64 Bit INT) QueryPerformanceCounter(value); // BOOOM! // ... free(value);Nun bin ich relativ ratlos. Eigentlich dachte ich, dass ich in C (habe meistens mit C++ gearbeitet), den Speicher relativ wahllos uminterpretieren kann, wenn nur die Anzahl der Bytes stimmt.
Meine zweite Frage:
Seht ihr, was ich falsch gemacht habe / vergessen habe zu tun oder was ich tun muss, um den Wert aus value zu kriegen? Bzw. seht irgendeinen anderen Grund, warum das Programm verreckt?
-
Beim gcc gibts glaube ich int64_t
-
Hast du dir den Prototype für
QueryPerformanceCounterjetzt selbst definiert? Falls ja, hast du vielleicht vergessen die Calling-Convention anzugeben? Das könnte leicht komische Abstürze verursachen, speziell wenn man danach Zeiger dereferenziert die aufm Stack liegen (Base-Pointer kaputt und so).BTW: wenn du dir die Union selbst definieren willst, wieso dann nicht so:
typedef union _LARGE_INTEGER_X { struct susi { DWORD LowPart; LONG HighPart; } su; struct strolchi { DWORD LowPart; LONG HighPart; } st; LONGLONG QuadPart; } LARGE_INTEGER_X, *PLARGE_INTEGER_X;Das sollte GCC dann auch fressen.
Bzw. noch einfacher:typedef struct _LARGE_INTEGER_X { LONGLONG QuadPart; } LARGE_INTEGER_X, *PLARGE_INTEGER_X;
-
Was den Problem mit LARGE_INTEGER angeht: hast du einfach mal versucht, ein
unionvor den Typ bei der Deklaration der Variablen anzugeben? Meines miesen C-Wissens wird durch eintypedefdies zwar unnötig gemacht, aber vielleicht hilft es ja:union LARGE_INTEGER MyOne;Ist aber eher unwahrscheinlich.
Was deinen Workaround angeht, so solltest du niemals versuchen, im Code eigene Konstanten für die Speicherbelegung anzugeben. Die meisten Compiler optimieren den Scheiß, den du eingibst, so grundlegend, dass das Speicherabbild einer Struktur hinterher nicht mehr viel mit dem ursprunglichen Objekt zu tun hat. Nur wenn du dir absolut sicher bist, kannst du dir dieses Vergnügen leisten, denn mehr ist es nicht ... der
sizeof-Operator gibt dir alles, was du brauchst (auch hier mal mitunionausprobieren).Ansonsten würde ich einmal versuchen, eine ganz kleine, eigenständige Union zu schreiben und zu schauen, ob der gcc das frisst. Wenn nicht, probiere mit
typedefvor der Typ- oder mitunionoderstructvor der Objektdeklaration aus, ob's so funktioniert.@hustbaer: kann es sein, dass du vermutest, dass er den Prototyp von
QueryPerformanceCounterselbst definiert hat? Ich frage mich nämlich, wie der Linker das linken kann ... ich meine, die Signatur stimmt ja nicht mehr mit den Bibliotheksfunktionen überein.
-
Vielen vielen Dank für die Antworten schon mal!
Am Dienstag, wenn ich wieder an dem entsprechenden PC arbeite, kann ich eure Tipps ausprobieren. Ich melde mich danach dann wieder.@hustbaer:
Nein, ich habe den Prototyp nicht selbst definiert. Da frisst er den aus der WinAPI (warum auch immer).@Glühbirne:
Wie der Linker das linken kann, frage ich mich auch, ich gucke am Montag mal nach der Signatur in der windows.h auf dem System und poste sie.
-
Glühbirne schrieb:
Was deinen Workaround angeht, so solltest du niemals versuchen, im Code eigene Konstanten für die Speicherbelegung anzugeben. Die meisten Compiler optimieren den Scheiß, den du eingibst, so grundlegend, dass das Speicherabbild einer Struktur hinterher nicht mehr viel mit dem ursprunglichen Objekt zu tun hat.
Äh, nein, das tun sie ganz sicher nicht.
@hustbaer: kann es sein, dass du vermutest, dass er den Prototyp von
QueryPerformanceCounterselbst definiert hat? Ich frage mich nämlich, wie der Linker das linken kann ... ich meine, die Signatur stimmt ja nicht mehr mit den Bibliotheksfunktionen überein.Ja, hatte ich angenommen. Ein leiser Hinweis darauf was dass ich ihn explizit danach gefragt habe.
Signatur ist doch Schnuppe so lange die Funktionen nicht mit dekorierten Namen gelinkt werden. "QueryPerformanceCounter" heisst in der LIB einfach "QueryPerformanceCounter" und nicht "_QueryPerformanceCounter@BLAH234".
-
Paul Manns schrieb:
@hustbaer:
Nein, ich habe den Prototyp nicht selbst definiert. Da frisst er den aus der WinAPI (warum auch immer).Sind das C-ohne-++ Files die da
QueryPerformanceCounteraufrufen? Ich frage mich nämlich wie das sonst jemals gehen soll, dass duQueryPerformanceCounterohne Cast mit einem void-Pointer aufrufst.
-
hustbaer schrieb:
Paul Manns schrieb:
@hustbaer:
Nein, ich habe den Prototyp nicht selbst definiert. Da frisst er den aus der WinAPI (warum auch immer).Sind das C-ohne-++ Files die da
QueryPerformanceCounteraufrufen? Ich frage mich nämlich wie das sonst jemals gehen soll, dass duQueryPerformanceCounterohne Cast mit einem void-Pointer aufrufst.Ja, findet (zu meinem Leidwesen) alles in C statt.
-
Wenn ich ein union der Definition voranstelle, sagt mir der Compiler fuer die Variablen:
"Storage size of 'BEZEICHNER' isn't known."
Der folgende Code
typedef struct _LARGE_INTEGER_X { LONGLONG QuadPart; } LARGE_INTEGER_X, *PLARGE_INTEGER_X; struct LARGE_INTEGER_X var;bricht ab mit:
ERROR: syntax error before LONGLONG
WARNING: no semicolon at end of struct or union (in der Zeile LONGLONG QuadPart;)
WARNING: data definition has no type or storage class
ERROR: storage size of var isn't knownFolgendes funktioniert auch nicht:
typedef struct { long long QuadPart; } LARGE_INTEGER_X, *PLARGE_INTEGER_X; struct LARGE_INTEGER_X var;ERROR: storage size of var isn't known
/Gerade bemerkt:
Folgender Code stuerzt nicht ab:long long * frequency // ... frequency = (long long *)malloc(8); QueryPerformanceFrequency(frequency);QueryPerformanceFrequency(frequency) liefert ausserdem true, allerdings ist das Ergebnis nach der Dereferenzierung eine negative Zahl (-1294507296), was mich etwas verwirrt.

Folgender Code stuerzt ausserdem allerdings weiter ab:
long long * tStart // ... tStart = (long long *)malloc(8); QueryPerformanceCounter(tStart);Zudem kriege ich die zwei folgenden Warnungen (wenn er fehlerfrei compiliert):
Warning: resolving _QueryPerformanceCounter by linking to _QueryPerformanceCounter
Warning: resolving _QueryPerformanceFrequency by linking to _QueryPerformanceFrequencyAus denen werde ich auch ueberhaupt nicht schlau.
Heisst das, dass er die beiden Funktionen nicht richtig gelinkt hat?
Warum gibt es dann keine Fehlermeldung?
Wieso funktioniert die eine und die andere nicht?
-
Ich habe jetzt eine Teilloesung des Problems.
LARGE_INTEGER laesst sich verwenden, wenn man Windows.h als erste der Headerfiles einbindet, da eine der Bibliotheken fuer die Simulationsumgebung CONST neudefiniert.
Jetzt sind die Abstuerze, Compilerfehler etc. schonmal vorbei.
Einzig komisch noch, dass QueryPerformanceFrequency eine negative Zahl als Ergebnis liefert.
-
Paul Manns schrieb:
Einzig komisch noch, dass QueryPerformanceFrequency eine negative Zahl als Ergebnis liefert.
Ist der Aufruf denn erfolgreich (returned es TRUE)!?