C++ - 64 位上的SP_DEVINFO_LIST_DETAIL_DATA_W大小

C++ - size of SP_DEVINFO_LIST_DETAIL_DATA_W on 64 bit

本文关键字:LIST DEVINFO DETAIL DATA 大小 SP C++      更新时间:2023-10-16

在 64 位上,SP_DEVINFO_LIST_DETAIL_DATA_W的大小为 560。不应该是554吗?

typedef struct _SP_DEVINFO_LIST_DETAIL_DATA_W {
  DWORD  cbSize;
  GUID   ClassGuid;
  HANDLE RemoteMachineHandle;
  WCHAR  RemoteMachineName[SP_MAX_MACHINENAME_LENGTH];
} SP_DEVINFO_LIST_DETAIL_DATA, *PSP_DEVINFO_LIST_DETAIL_DATA;

cbSize 为 4,ClassGuid 为 16,RemoteMachineHandle 为 8(64 位),RemoteMachineName 为 2*(260+3) (SP_MAX_MACHINENAME_LENGTH 为 MAX_PATH + 3)

所以,4+16+8+2*263=554。为什么 sizeof(_SP_DEVINFO_LIST_DETAIL_DATA_W) 返回 560 ?

您忽略了对齐字段的要求,这对于确保处理器可以有效地访问它们非常重要。 HANDLE 类型为 64 位,8 字节,当您以 x64 为目标时。 因此,RemoteMachineHandle 成员与 8 的倍数的偏移对齐。 这会将其从偏移量 20 移动到偏移量 24,下一个偏移量可被 8 整除。 额外的 4 个字节是填充的,未使用。

这使得结构大小为 4 + 16 + 4 + 8 + 2*263 = 558 字节。

还有一个额外的问题 - 此结构的数组会使句柄再次未对齐。 索引 1 处的元素的句柄偏移量为 558 + 4 + 16 + 4 = 582。 这不是 8 的倍数,成员将再次错位。

因此

,编译器在结构的末尾添加了额外的 2 个字节的填充,因此结构的总大小是 8 的倍数。 因此:

Offset  Size    Member
   0      4     cbSize
   4     16     ClassGuid
  20      4     -
  24      8     RemoteMachineHandle
  32    526     RemoteMachineName
 558      2     -
-------------
        560

我猜填充以适应某些成员的对齐要求。但是,我不熟悉这些类型,因此我无法解释此结构的对齐方式。

如果您真的想以最有效的方式打包结构,则可以按大小(递减)对成员进行排序。通常不允许编译器对成员重新排序。

我尝试使用SetupDiGetDeviceInfoListDetail,但大小也错误。 终于我找到了解决方案

这是结构体的定义

typedef struct _SP_DEVINFO_LIST_DETAIL_DATA {
  DWORD  cbSize;
  GUID   ClassGuid;
  HANDLE RemoteMachineHandle;
  TCHAR  RemoteMachineName[SP_MAX_MACHINENAME_LENGTH];
} SP_DEVINFO_LIST_DETAIL_DATA, *PSP_DEVINFO_LIST_DETAIL_DATA;

在设置中API.h

#define SP_MAX_MACHINENAME_LENGTH   (MAX_PATH + 3)

https://msdn.microsoft.com/en-us/library/cc249520.aspx

MAX_PATH 0x00000104

那里为

[StructLayout(LayoutKind.Sequential,Pack = 1, CharSet = CharSet.Ansi)]
    public struct  SP_DEVINFO_LIST_DETAIL_DATA
    {
        public uint cbSize;
        public Guid classGuid;
        public int RemoteMachineHandle;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 263)]public string RemoteMachineName;
    };