这两种结构有什么区别?涉及到IT技术相关内容,是一个提问标题。

4

我想把这个结构作为参数传递给一个PInvoke函数,有两种方式可以定义这个结构。我想知道这两种方式之间的区别。

[StructLayout(LayoutKind.Sequential)]
public struct Rect {
   public int left;
   public int top;
   public int right;
   public int bottom;
}   

[StructLayout(LayoutKind.Explicit)]
public struct Rect {
   [FieldOffset(0)] public int left;
   [FieldOffset(4)] public int top;
   [FieldOffset(8)] public int right;
   [FieldOffset(12)] public int bottom;
}

根据我在这里找到的布局定义,两者在内存中不应该看起来相同吗?是否有一个比另一个更好的优势?

1
第一个是合理的,而第二个不是。 - David Heffernan
3个回答

5

我在这里找到的布局定义,它们不应该在内存中都看起来相同吗?

是的,在内存中它们看起来是相同的。

有没有一个比另一个更有优势呢?

其中一个打字更快,更容易阅读。


当然,使用FieldOffset是一个有用的工具;它并不总是无用的,但如果你碰巧使用它来明确地布置字段,以按照默认方式进行布置,那么它就是无用的。如果您使用它来布置字段以其他方式(例如,重叠,添加填充空间,使底层表示与声明顺序不同等),那么它就不是无用的。


如果你不需要进行任何复杂的操作,比如重新排序、使用填充调整间距等,我同意第一个版本更简单,更易于维护,并且会减少错误。当你想要添加一个字段时会发生什么(现在你必须进行计算,可能会出错)。 - Nick Bray

1
理论上,这两者完全相同。通常在与非托管代码交互时,您会使用显式布局。这很重要,因为将来“int”可能不再具有32位,这意味着顺序布局可能不再适用。希望这能有所帮助! 编辑 还有一个想法是,如果您正在将.NET结构映射到未经管理的联合或在.NET中使用与非托管代码中不同的类型,这将非常有用。 第二次编辑 其他人指出,微软将“永远”不会更改int的大小。我同意这将是一种破坏性的变化,因此极其不可能。尽管如此,在.NET和非托管代码之间传输值时明确结构映射仍然是一个好主意。特别是如果未经管理的结构/布局将来可能发生变化。

将来的情况下,“int”可能不再有32位。这绝对不是真的。在C#中,“int”只是“System.Int32”的别名。它将始终为32位,而不像C++那样仅定义了最小大小。 - Servy
@Servy 我想你是正确的,但微软有可能在某个时候更改编译器(当然不会没有警告)。到那时,所有这些值都需要使用显式布局进行重新映射。 - drew_w
2
@drew_w:不会的;微软绝对不会改变int的大小。那将是最大的破坏性变更之一。 - SLaks
@drew_w 确实指针大小会改变。已经有32位和64位的运行时了。关键是int不是一个字的大小。语言规范明确规定它是32位。他们可以创建一个新类型,它是一个整数类型,大小为一个字,但他们不会改变intlong也是固定的。它始终是64位,而不是一个字或两个字等大小。它只是64位。这就是规范所说的。否则就会违反语言自身的定义。 - Servy
@Servy 我认为这可能是一场哲学讨论,因为没有人能够真正预测未来。我同意 原则上 他们不会改变这个,但是仅仅引用当前文档作为理由是不够的。文档是与语言版本相关的。随着 .NET 的新版本发布,整数的大小可能会发生变化,文档将被更新。再次强调 - 我同意这不是一个明智的改变,也不是我预测的改变,但严格来说,这是可能的。 - drew_w
显示剩余2条评论

0

我认为针对这个问题,不存在一个真正更好的布局版本。不过第二个版本使用了 ExplicitLayoutKind,可以让你通过设置 fieldoffest 来改变结构体成员的顺序。

在我看来,第二个版本更容易扩展。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接