В чем разница между unsigned long и unsigned int и как эти 2 типа должны быть маршалированы в c#?

Итак, я «переводил» пару структур с C / C++ на C# и наткнулся на кое-что, чего я действительно не понимаю ...

Вот первая структура:

typedef struct _MOUSE_EVENT_RECORD {
COORD dwMousePosition;
DWORD dwButtonState;
DWORD dwControlKeyState;
DWORD dwEventFlags;
}

который я написал как:

[StructLayout(LayoutKind.Sequential)]
public struct MouseEventRecord
{
    [MarshalAs(UnmanagedType.LPStruct)]
    public Coord dwMousePosition; //struct with (short X) & (short Y)
    [MarshalAs(UnmanagedType.U4)]
    public ButtonState dwButtonState; //A uint enum
    [MarshalAs(UnmanagedType.U4)]
    public ControlKeyState dwControlKeyState; //A uint enum
    [MarshalAs(UnmanagedType.U4)]
    public MouseEventFlags dwEventFlags; //A uint enum
}

И вот эта структура:

typedef struct _CONSOLE_READCONSOLE_CONTROL {
    ULONG nLength;
    ULONG nInitialChars;
    ULONG dwCtrlWakeupMask;
    ULONG dwControlKeyState;
}

который я написал как:

    [StructLayout(LayoutKind.Sequential)]
    public struct ConsoleReadConsoleControl
    {
        [MarshalAs(UnmanagedType.U4)]
        public uint nLength;
        [MarshalAs(UnmanagedType.U4)]
        public uint nInitialChars;
        [MarshalAs(UnmanagedType.U4)]
        public uint dwCtrlWakeupMask;
        [MarshalAs(UnmanagedType.U4)]
        public ControlKeyState dwControlKeyState; //A uint enum
    }

Теперь я не уверен, правильно ли это, причина, по которой я написал ULONG как public uint, заключается в том, что ULONG (который является внутренним unsigned long) имеет размер 4 байта (сделал sizeof (unsigned long) и sizeof (unsigned int), оба из которых вернули 4 ) но тогда в чем разница между DWORD (unsigned int) и ULONG (unsigned long), если они оба имеют размер 4 байта? И правильно ли написаны "переведенные" структуры?

Я читал в документации GNU, что unsigned long зависит от архитектуры системы, поэтому unsigned long может быть 64-битным, как и unsigned long long int. Я не совсем понимаю это, потому что мой компьютер работает под управлением 64-битной Windows, так что не должен ли sizeof(unsigned long) возвращать 8, а не 4?

Действительно, sizeof (unsigned long) должен был вернуть вам 8, если вы используете 64-битную систему. Вероятно, вы скомпилировали его для 32-битной системы.

Benjamin Barrois 10.08.2018 16:38

@BenjaminBarrois - нет, если он находится в коробке с Windows, где long 32-битный - даже для 64-битной программы.

Martin Bonner supports Monica 10.08.2018 16:38

Windows по-прежнему использует 32-битную длину в 64-битных системах. * Nix использует 64-битную длину в 64-битных системах. Если вам нужны известные типы ширины в C++, используйте типы intNN_t, где NN - разрядность.

NathanOliver 10.08.2018 16:39

@MartinBonner Хорошо, я этого не знал! Я привык писать код только в системах Unix.

Benjamin Barrois 10.08.2018 16:44

@MartinBonner Windows Box? Первый раз, когда я слышу об этом, я получил окна через инструмент создания мультимедиа (можно найти на веб-сайте MS)

User90482049 10.08.2018 16:44

«Коробка» = компьютер, ПК, машина. Другими словами, «если вы работаете в системе Windows» (что, очевидно, так и есть, потому что эти типы взяты из Windows API).

Martin Bonner supports Monica 10.08.2018 16:46

Нет никакой разницы, компиляторы, которые генерируют код для Windows, используют Модель данных LLP64. В основном историческая случайность, Windows началась с 16-битной версии, поэтому существует много long. LLP64 был самым простым способом обеспечить переносимость.

Hans Passant 10.08.2018 16:50

Я думаю, что часть вашей проблемы заключается в том, что вы сказали ему маршалировать dwMousePosition как LPStruct. В _MOUSE_EVENT_RECORD dwMousePosition - это COORD, а не указатель на COORD.

OldFart 10.08.2018 17:17

@OldFart, тогда как его маршалировать? Или его не следует маршалировать как-нибудь?

User90482049 10.08.2018 17:44
2
9
776
1

Ответы 1

Это смущает.

Во-первых, в Windows нет разницы между unsigned long и unsigned int (за исключением того, что они разных типов, поэтому вы можете перегружать функции на них). Ваш код маршаллинга в порядке.

На большинстве других платформ int - 32-битный, long long - 64-битный, а long - 32-битный в 32-битной программе и 64-битный в 64-битной программе. (В этом случае IntPtr будет подходящей декларацией маршаллинга - он правильно переключает размер).

А в те времена, когда было 16 бит, int был 16-битным, а long - 32-битным. Стандарт C и C++ никогда не определял точные размеры бит для целочисленных типов, они всегда зависят от реализации. Стандарт гарантирует только то, что sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) и то же самое для соответствующих типов unsigned.

Remy Lebeau 10.08.2018 19:02

При маршалинге метода, который принимает целое число размером с указатель (например, long в Unix, которое может быть 32- или 64-битным), вы можете / должны использовать IntPtr в C#. Это позволяет вам сохранить вашу сборку AnyCPU, поддерживая как 32-битные, так и 64-битные среды.

Zastai 25.08.2018 19:40

@Zastal: Ой! Хорошая точка зрения. Я исправлю (даже если у него могут быть проблемы на 128-битных платформах - я не ожидаю увидеть что-либо из них в течение 50 лет).

Martin Bonner supports Monica 26.08.2018 10:09

Другие вопросы по теме