Forum: PC-Programmierung fehlender Compilerfehler/Warnung


von donvido (Gast)


Lesenswert?

Ahoi,

ich habe hier ein interessantes Phänomen mit Visual Studio Express 2013.
Und zwar erzeuge ich eine DLL in C, die in einem Delphiprogramm 
eingebunden wird.
Ich bekomme keine Warnung bzw. keinen Compilerfehler, wenn meine 
Funktion im Header nicht korrekt deklariert ist.
Das Einbinden im Delphicode (dort werden auch Parameter übergeben) 
funktioniert aber einwandfrei.

foo.h
1
#ifdef __cplusplus
2
#define EXPORT extern "C" __declspec (dllexport)
3
#else
4
#define EXPORT __declspec (dllexport)
5
#endif;
6
7
8
EXPORT char* bar();

foo.c
1
#include "foo.h"
2
3
char* bar(bool var1, int var2, char* var3, double* var4){
4
do_something();
5
};

Wie kann das sein?

: Verschoben durch User
von Walter T. (nicolas)


Lesenswert?

Ich kenne Delphi nicht, aber generell kann man aus einer DLL den Header 
korrekt extrahieren (z.B. DLLtool). Kann sein, daß Delphi die Header gar 
nicht benutzt.

von Dr. Sommer (Gast)


Lesenswert?

donvido schrieb:
> wenn meine Funktion im Header nicht korrekt deklariert ist.

Was ist denn deiner Meinung nach falsch? Wenn du bar() schreibst, 
bedeutet das "beliebige Parameter beliebigen Typs". Das ist kompatibel 
zu den angegebenen Parametern. Wenn du wirklich "keine Parameter" haben 
willst, musst du "bar(void)" schreiben.

von Walter T. (nicolas)


Lesenswert?

Dependency Walker hieß das nette Tool von Microsoft.

von Adam P. (adamap)


Lesenswert?

Ich denke eher, dass der Compiler dir nichts mitteilt, da du diese 
Funktion in diesem Zusammenhang nirgends aufrufst.

Habs mal mit dem VS 2015 getestet.
1
char* bar();
2
3
char* bar(bool var1, int var2, char* var3, double* var4)
4
{
5
    printf("FOO");
6
    return var3;
7
};
8
9
int main()
10
{
11
    char x;
12
    double y;
13
14
    /* geht */
15
    bar(true, 1, &x, &y);
16
17
    /* geht nicht */
18
    bar();
19
}

Beim Aufruf der bar() liefert der Compiler dann:
error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""char * 
__cdecl bar(void)" (?bar@@YAPADXZ)" in Funktion "_main".

Für den Compiler sind es wohl "überladene Funktionen" wobei er für bar() 
keine Funktionsdefinition finden kann.

von donvido (Gast)


Lesenswert?

Dr. Sommer schrieb:
> donvido schrieb:
>> wenn meine Funktion im Header nicht korrekt deklariert ist.
>
> Was ist denn deiner Meinung nach falsch? Wenn du bar() schreibst,
> bedeutet das "beliebige Parameter beliebigen Typs". Das ist kompatibel
> zu den angegebenen Parametern. Wenn du wirklich "keine Parameter" haben
> willst, musst du "bar(void)" schreiben.

Okay, das mit "beliebige Parameter" war mir nicht ganz bewusst. Mich 
hats nur gewundert, dass das nichtmal in irgend einer Weise markiert 
wurde.

von donvido (Gast)


Lesenswert?

Adam P. schrieb:
> Ich denke eher, dass der Compiler dir nichts mitteilt, da du diese
> Funktion in diesem Zusammenhang nirgends aufrufst.

Ja, das klingt plausibel. Danke

von Dr. Sommer (Gast)


Lesenswert?

Adam P. schrieb:
> Beim Aufruf der bar() liefert der Compiler dann:
> error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""char *
> __cdecl bar(void)" (?bar@@YAPADXZ)" in Funktion "_main".

Du hast als C++ kompiliert. Da sind die Regeln anders.

von Adam P. (adamap)


Lesenswert?

Dr. Sommer schrieb:
> Du hast als C++ kompiliert. Da sind die Regeln anders.

Kann man etwa im VS2013 als C kompilieren?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Adam P. schrieb:
> Kann man etwa im VS2013 als C kompilieren?

Natürlich, wenn die Sourcefiles *.c heißen, wird der native C-Compiler 
verwendet. Der ist etwas angestaubt (d.h. kennt kein C99 oder neuer), 
aber funktioniert davon abgesehen vorzüglich.

von Jim M. (turboj)


Lesenswert?

donvido schrieb:
> Das Einbinden im Delphicode (dort werden auch Parameter übergeben)
> funktioniert aber einwandfrei.

64-Bit oder 32-Bit?

In 32-Bit können verschiedene Aufruf-Konventionen zu lästigen Stack 
Überläufen führen. Das merkt man aber oft nur bei sehr vielen Aufrufen 
und kleinem Stack.

In 64-Bit ist das Aufräumen des Stacks einheitlich gelöst, calling 
conventions sind hier IIRC no-ops.

von Jim M. (turboj)


Lesenswert?

Nochwas: Es gibt mehrere Möglichkeiten wie ein Symbol einer DLL 
exportiert und in Delphi importiert wird. Einige davon ignorieren 
Unterschiede bei Calling Conventions.

von Kammerjäger (Gast)


Lesenswert?

Adam P. schrieb:
> Kann man etwa im VS2013 als C kompilieren?

Ja, über die Dateiendung (siehe Rufus) oder per Flag /Tc.

Der Schwerpunkt liegt auch bei neueren Versionen des MS-Compilers klar 
auf C++.

"The Visual C++ C compiler is generally compatible with the ISO C99 
standard, but not strictly compliant. In most cases, portable C code 
will compile and run as expected. Visual C++ does not support most of 
the changes in ISO C11."

Man kann inzwischen aber wohl auch Clang (Windows, Android, iOS) und GCC 
(Android, Linux - Remote oder über das Linux-Subsystem) in VS verwenden.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Dr. Sommer schrieb:
> Was ist denn deiner Meinung nach falsch? Wenn du bar() schreibst,
> bedeutet das "beliebige Parameter beliebigen Typs". Das ist kompatibel
> zu den angegebenen Parametern.

Nicht ganz. Ein Funktionsprototyp ist inkompatibel zu einer K&R-
Deklaration, wenn er Argumenttypen enthält, die einer Promotion
unterworfen sind. Dazu zählt auch bool, wenn es über stdbool.h als _Bool
definiert ist. Der Compiler müsste deswegen einen Fehler ausgeben.

Gibt er keinen Fehler aus, kann es daran liegen, dass

- bool nicht mittels stdbool.h als _Bool, sondern durch den Benutzer als
  int oder unsigned int definiert ist,

- das MS-spezifische __dllspec(dllexport) die beiden Deklarationen
  kompatibel macht (mit diesen MS-Erweiterungen kenn ich mich nicht aus)
  oder

- der Compiler einen Bug hat.

Bei folgendem Code

1
#include <stdbool.h>
2
3
char *bar();
4
5
char *bar(bool var1, int var2, char *var3, double *var4) {
6
  return 0;
7
}

sollte der C-Compiler auf jeden Fall meckern.

: Bearbeitet durch Moderator
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.