Marshal.Sizeof() 返回意外值

Posted

技术标签:

【中文标题】Marshal.Sizeof() 返回意外值【英文标题】:Marshal.Sizeof() returning unexpected value 【发布时间】:2020-12-08 01:29:27 【问题描述】:

我正在调试由第 3 方编写的 C# 代码。该项目是一个旧的 C++ 项目,由承包商用 C# 重写,我无权访问承包商。我编写了原始的 C++ 版本。

问题在于,当 C# 代码获取表示通过 UDP 连接接收的数据的结构的大小时。

结构体定义为:

[StructLayout(LayoutKind.Sequential,Pack=1)]
internal class PROXY_HDR 
    public ushort pad;
    public ushort label;
    public char flags;
    public ushort length;
    public char[] ip = new char[4];
    public ushort port;

这个结构的大小被检索为:

int size = Marshal.Sizeof(typeof(PROXY_HDR));

并且返回的值是 17 而不是预期的 13。有 4 个字节的差异,我怀疑 ip 成员,但这只是因为它的表达方式与其他成员不同(使用 'new' ),但我没有其他决定依据。

我通常不会在我的 C# 代码中使用这种类型的封送处理来毫无问题地解析接收到的数据包,所以我不知道如何修改这个结构定义以使其与原始版本大小“对齐”-明智的。

我可以用

替换元帅线
int size = 13;

但那是作弊,对吧?

我可以通过某种方式修改此布局以使尺寸正确吗?

【问题讨论】:

我没有实际答案,但您可以尝试像我在 this answer 中针对不相关问题所做的那样明确设置字段偏移量。 你为什么希望它是 13? @IanKemp 因为对于 x86(32 位)它确实返回 13,如果编译 x64 则返回 +4... @AlexeiLevenkov -- 如果你正确编组它,它会在 64 位 32 位 下返回 13 个字节 @Andy 确实 - 也没有问题要问:) 显然,每天不做这些事情的人都不会期望 char 有 sizeof = 1 ... 而 OP 不知道引用类型...有很多东西要解释。 【参考方案1】:

将此添加到结构中:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal class PROXY_HDR

    public ushort pad;
    public ushort label;
    public byte flags;
    public ushort length;
    [MarshalAs(UnmanagedType.ByValArray,
        SizeConst = 4, ArraySubType = UnmanagedType.U1)]
    public byte[] ip;
    public ushort port;

这将告诉编译器将其视为典型的 C 样式数组,而不是指针。这应该是字节,因为 IP 地址是一个无符号字符数组。 char 通常不用于这些类型的标头中,通常是 byte(即:unsigned char

【讨论】:

@Bathsheba -- 我认为是对的。我的解释表明我不是100%确定为什么是对的。我将不得不对此进行研究并提出更好的解释。 @Andy:是的,这行得通。至于 'char' 的定义,我认为 C# 开发人员试图尽可能忠实于原始 C++ 代码,并且这个特定的结构从未像大多数其他结构一样更新为使用 'byte'。谢谢!! 请注意,最初的问题只是由于将 ip 视为指针(32 位或 64 位,取决于您编译代码的方式)。显然char 是默认编组的单字节 - 我没有要确认的链接,但您可以轻松尝试自己(并直接查看大小 = 13 或 17,只能通过 char = 1 的大小来解释)。 @user3235770 -- 请注意,您可以通过在属性中添加ArraySubType = UnmanagedType.U1 或其他任何内容来使其更具体。我不知道这是否会有所帮助。 实际上我只是注意到我只添加了 MarshalAs 行,而不是在后面的行中从 CHAR 更改为 BYTE。很明显,这是作为指针的解释。

以上是关于Marshal.Sizeof() 返回意外值的主要内容,如果未能解决你的问题,请参考以下文章

Marshal.SizeOf 给出错误的大小

在啥情况下 Marshal.SizeOf 在堆上分配?

c#/c++ 如何将结构的结构与 marshal.sizeof 联合

java 不兼容的类型 意外的返回值

计算平均值时的意外返回值?

Java布尔“意外的返回值”