Обработка разных неуправляемых целочисленных размеров - PullRequest
8 голосов
/ 08 апреля 2011

У меня есть библиотека Си. Он имеет много вызовов функций, таких как:

void init_foo( unsigned long x, unsigned long y );

Сама библиотека динамически загружается во время выполнения (скорее как плагин). Заголовки одинаковы для всех платформ.

Моя проблема в том, что в Windows и 32-разрядной версии Linux длина без знака составляет 32 бита, а в 64-разрядной версии Linux - 64 бита.

Различные реализации этой библиотеки все принимают это, вам нужно собрать свою программу на C для правильной целевой платформы (как и ожидалось).

Мой метод взаимодействия должен быть одним из них в зависимости от архитектуры.

#if lin64
[DllImport("libfoo")]
public static void init_foo( Uint64 x, Uint64 y );
#else
[DllImport("libfoo")]
public static void init_foo( Uint32 x, Uint32 y );
#endif

Типы C #, которые я могу использовать, имеют фиксированный размер на всех платформах (как и должно быть). Так что мой управляемый long , переданный из .Net / Mono, всегда будет неуправляемым uint64_t .

Как я могу справиться с этим переменным целочисленным размером, при этом имея одну сборку, которая будет работать в .Net или моно в 32-битном или 64-битном режиме?

Ответы [ 2 ]

4 голосов
/ 08 апреля 2011

Проблема в том, что на 64-битной Windows C long все еще 32-битная в отличие от Linux, где она 64-битная, и это вызывает некоторую боль.

Если вы не планируете поддерживать 64-битную Windows, это просто - вы можете сопоставить long с IntPtr в вашем определении DllImport. IntPtr является 32-битным на 32-битных окнах и Linux, что совпадает с длиной. Длинный в 64-битном Linux также является 64-битным, как и IntPtr, однако в Windows 64-битном, в то время как IntPtr в 64-битном является 32-битным.

Если вы хотите поддерживать 64-битную Windows, вы можете определить две подписи одновременно - одну для 64-битной и одну для 32-битной:

[DllImport("libfoo", EntryPoint="init_foo")]
public static void init_foo_64bit( Uint64 x, Uint64 y );

[DllImport("libfoo", EntryPoint="init_foo")]
public static void init_foo_32bit( Uint32 x, Uint32 y );

Затем в своем коде вы можете динамически решить, какой из них вызывать так:

public void InvokeFoo(long x, long y)
{
    if (Environment.Is64BitProcess)
        return init_foo_64bit(x, y);
    return init_foo_32bit((int)x, (int)y);
}

P.S .: Если вы не используете .NET 4, другой способ проверить, является ли вы 64-битным процессом, будет bool is64Bit = IntPtr.Size == 8

0 голосов
/ 04 июля 2011

Другой возможностью было бы написать другую библиотеку C с одним API, который не различается между платформами .Net, и вместо этого поставлять правильную библиотеку-оболочку для каждой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...