c ++ - mingw DLL fra C #: Hvorfor skal jeg tilsidesætte ny/slette?
Problem
Jeg forsøger at kalde en minimal C-funktion fra C # på Windows 10. Jeg bruger mingw/g ++ til at kompilere C-koden i en .dll
Det viser sig, at jeg skal definere
opterator new[]
eller kompilere .dll ved hjælp af Visual Studio. Ellers styrter mit C # -program med følgende fejl:The program '[14740] Test.exe' has exited with code -1073741819 (0xc0000005) 'Access violation'.
Jeg vil virkelig gerne forstå, hvad der sker lige her, og hvordan jeg kan løse dette problem uden at overstyre alle de nye/slette operatører, men stadig bruger mingw.
Her er det minimale eksempel, der gengiver fejlen, herunder en løsning (hvis
AddNewOperator
er defineret operator new[]
, vil blive defineret, og den resulterende .dll vil fungere fint):Test.cs (kompileret/køre med Visual Studio 2017):
using System;
using System.Runtime.InteropServices;
class Program
{
[DllImport("libTest", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)]
public static extern int TestFunction();
static void Main(string[] args)
{
Console.WriteLine("!!" + TestFunction());
}
}
Test.cpp kompileret med mingw (se nedenfor):
#include <new>
#include <cstdlib>
#ifdef AddNewOperator // This will fix the issue
void* operator new[](std::size\_t sz){
return std::malloc(sz);
}
#end
extern "C" {
int \_\_stdcall \_\_declspec(dllexport) TestFunction() {
int* test = new int[3]; // removing this line will make everything work when building
return test[2];
}
Og her er build scriptet:
# Remove the following # and the compiled dll will work just fine
g++ -g -s -Wall -c -fmessage-length=0 Test.cpp #-DAddNewOperator
g++ -g -shared -o libTest.dll *.o -Wl,--subsystem,windows
kompilere alt for x86 i stedet for 64 bit løser også problemet (hvilket igen ikke er nogen mulighed for mig)
Bedste reference
TL; DR
Du må ikke blande tildeling/deallokering mellem kompilatorer!
Det problem, du står over for, er ret vanskelig og faktisk skal dit program kollidere hver gang, med eller uden definitionen
void* operator new[](size\_t){...}
.Hvis du fejler dit program, skal det faktisk gå i stykker, mens du sletter din
test
-variabel. Denne variabel er oprettet ved hjælp af mingws nye operatør, men slettet ved hjælp af MSVC sletter operatør, og de er ikke interoperable. Så du skal bruge mingws delete
funktion. [16]For en simpel test kan du bare gøre:
c + + kode:
int* test = nullptr;
int \_\_stdcall \_\_declspec(dllexport) TestFunction() {
test = new int[3]; // note test is global
return test[2];
}
void \_\_stdcall \_declspec(dllexport) CleanUp() {
delete[] test;
}
c # kode:
public static extern int TestFunction();
public static extern int CleanUp();
static void Main(string[] args)
{
Console.WriteLine("!!" + TestFunction());
CleanUp();
}
Hvorfor kolliderer dit program ikke, hvis du omdefinerer den nye operatør?!
Jeg ved faktisk ikke sikkert, men jeg tror, at malloc-implementeringen af mingw bruger arv C runtime, der bruger HeapAlloc til tildeling og HeapFree til at slette din
test
-variabel. Kort sagt, du er simpelthen heldig/uheldig, det er ikke krasje, når du brugerdefinerede din operator new
og brugte malloc
indenfor ... Men hvis du kompilerer det ved hjælp af Visual Studio, bruger både (dll og exe) samme runtime, så allokering/deallokering sker inden for samme hukommelsesplads arrangør. MEN stadig er det UB, og du vil løbe ind i problemer! For eksempel: Hvis du opretter din libary med msvc10 og vil bruge dette bibliotek med msvc14, kan det samme ske her! Jeg kan huske nogle problemer med kode der kommer fra en fejl, hvor hukommelsen også blev forvaltet forkert; Vi brugte et bibliotek oprettet med msvc11, men vores kode blev kompileret med msvc12 ...