Я поигрался с кодом из этого примера хостинга dotnet и столкнулся с некоторыми проблемами.
Вот как я получаю указатель на функцию:
component_entry_point_fn function = nullptr;
int rc = functionPointer(
dllPath.c_str(),
dotnetType.c_str(),
methodName.c_str(),
nullptr,
nullptr,
(void**)&function);
И тогда я назвал это:
struct test {
const char* str = "from host!";
int i = 1;
} testArgs;
function(&testArgs, sizeof(testArgs));
И это работает нормально. Выход:
Hello, world! from Lib [count: 1]
-- message: from host!
-- number: 1
Hello again, world! from Lib [count: 2]
-- message: from host!
-- number: 1
Но когда я пытаюсь передать аргументы в виде кортежа:
std::tuple<FunctionArgs...> argsTuple = std::make_tuple(args...);
function(&argsTuple, sizeof(argsTuple));
Я понял:
Hello, world! from Lib [count: 1]
Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at System.SpanHelpers.IndexOfNullByte(Byte*)
at System.Runtime.InteropServices.Marshal.PtrToStringUTF8(IntPtr)
at Scripts.Lib.PrintLibArgs(LibArgs)
at Scripts.Lib.HelloAgain(IntPtr, Int32)
Код со стороны C# такой же, как в примере по ссылке выше. Еще один немаловажный факт – на Arm MacOS все работает без ошибок. Ошибка появляется в Linux x86_64. Компилятор везде один и тот же: clang.
sizeof для структуры и кортежа одинаковый — 16 байт. Попробовал добавить выравнивание:
alignas(16) std::tuple<FunctionArgs...>
argsTuple = std::make_tuple(args...);





все MSVC, gcc и clang на архитектуре x64, кажется, меняют порядок элементов кортежа в памяти https://godbolt.org/z/PW55PfGGE, но это деталь реализации, а не то, на что вы можете положиться. ваш код.
вам не следует передавать кортежи C++ в интерфейс C, они не предъявляют никаких требований к макету.
Возможно кому-то это понадобится, вот как я это сделал:
size_t bufferSize = ((sizeof(args) + ...) + sizeof(void*) - 1) / sizeof(void*) * sizeof(void*);
unsigned char* buffer = new unsigned char[bufferSize];
size_t offset = 0;
((std::memcpy(buffer + offset, &args, sizeof(args)), offset += sizeof(args)), ...);
function(buffer, bufferSize);
delete[] buffer;