Marshal.SizeOf 和 sizeof 之间的区别,我只是不明白

2024-01-16

到目前为止,我一直认为 Marshal.SizeOf 是计算非托管堆上 blittable 结构的内存大小的正确方法(这似乎是 SO 以及网络上几乎所有其他地方的共识)。

但在阅读了一些针对 Marshal.SizeOf 的警告之后(本文 https://www.codeproject.com/Articles/32125/Unmanaged-Arrays-in-C-No-Problem在“但是有一个问题......”之后)我尝试了一下,现在我完全困惑了:

public struct TestStruct
{
    public char x;
    public char y;
}

class Program
{
    public static unsafe void Main(string[] args)
    {
        TestStruct s;
        s.x = (char)0xABCD;
        s.y = (char)0x1234;

        // this results in size 4 (two Unicode characters)
        Console.WriteLine(sizeof(TestStruct));

        TestStruct* ps = &s;

        // shows how the struct is seen from the managed side... okay!      
        Console.WriteLine((int)s.x);
        Console.WriteLine((int)s.y);

        // shows the same as before (meaning that -> is based on 
        // the same memory layout as in the managed case?)... okay!
        Console.WriteLine((int)ps->x);
        Console.WriteLine((int)ps->y);

        // let's try the same on the unmanaged heap
        int marshalSize = Marshal.SizeOf(typeof(TestStruct));
        // this results in size 2 (two single byte characters)
        Console.WriteLine(marshalSize);

        TestStruct* ps2 = (TestStruct*)Marshal.AllocHGlobal(marshalSize);

        // hmmm, put to 16 bit numbers into only 2 allocated 
        // bytes, this must surely fail...
        ps2->x = (char)0xABCD;
        ps2->y = (char)0x1234;

        // huh??? same result as before, storing two 16bit values in 
        // only two bytes??? next will be a perpetuum mobile...
        // at least I'd expect an access violation
        Console.WriteLine((int)ps2->x);
        Console.WriteLine((int)ps2->y);

        Console.Write("Press any key to continue . . . ");
        Console.ReadKey(true);
    }
}

这里出了什么问题?字段解引用运算符“->”采用什么内存布局? “->”是否是用于寻址非托管结构的正确运算符?或者 Marshal.SizeOf 对于非托管结构来说是错误的大小运算符?

我没有找到任何可以用我理解的语言来解释这一点的东西。除了“……结构布局是不可发现的……”和“……在大多数情况下……”之类的软弱无力的东西。


区别在于:sizeof运算符采用类型名称并告诉您需要为该结构的实例分配多少字节的托管内存。这不一定是堆栈内存;当结构是数组元素、类的字段等时,它们会从堆中分配。相比之下,Marshal.SizeOf采用类型对象或类型实例,并告诉您需要分配多少字节的非托管内存。由于多种原因,这些可能会有所不同。类型的名称给了你一个线索:Marshal.SizeOf旨在将结构封送到非托管内存时使用。

两者之间的另一个区别是sizeof运算符只能采用非托管类型的名称;即结构体类型,其字段仅为整型、布尔值、指针等。 (有关准确定义,请参阅规范。)Marshal.SizeOf相比之下,可以采用任何类或结构类型。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Marshal.SizeOf 和 sizeof 之间的区别,我只是不明白 的相关文章

  • WinForms:如何确定窗口是否不再活动(没有子窗口具有焦点)?

    我的应用程序使用多个窗口 我想隐藏一个特定窗口 以防应用程序失去焦点 当活动窗口不是应用程序窗口时 source https stackoverflow com questions 466354 how can i tell if a wi
  • 在C语言中使用“void”

    我很困惑为什么我们需要通过void转换为 C 函数 int f void return 0 versus int f return 0 什么是正确的做法以及为什么 In C int f 是一种老式的声明 它说f需要固定但未指定数量和类型的参
  • 在搜索 List 时,为什么 Enumerable.Any(Func predicate) 比带有 if 语句的 foreach 慢

    最近有件事引起了我的好奇心 Why is the Enumerable Any Func
  • 我的线程图像生成应用程序如何将其数据传输到 GUI?

    Mandelbrot 生成器的缓慢多精度实现 线程化 使用 POSIX 线程 Gtk 图形用户界面 我有点失落了 这是我第一次尝试编写线程程序 我实际上并没有尝试转换它的单线程版本 只是尝试实现基本框架 到目前为止它是如何工作的简要描述 M
  • 为什么我不能用 `= delete;` 声明纯虚函数?

    Intro 纯虚函数使用通用语法声明 virtual f 0 然而 自 c 11 以来 有一种方法可以显式地传达non existence 特殊 成员函数的 Mystruct delete eg default constructor Q
  • 32 位应用程序的特征最大矩阵大小

    所以 我正在寻找Eigen http eigen tuxfamily org index php title Main Page当我尝试声明大于 10000x10000 的矩阵时 包崩溃 我需要声明一个像这样的矩阵 可靠地大约有 13000
  • C# 中的接口继承

    我试图解决我在编写应用程序时遇到的相当大的 对我来说 问题 请看这个 为了简单起见 我将尝试缩短代码 我有一个名为的根接口IRepository
  • Clang 编译器 (x86):80 位长双精度

    我正在尝试在 x86 Windows 平台上使用本机 80 位长双精度 海湾合作委员会选项 mlong double 80 https gcc gnu org onlinedocs gcc x86 Options html似乎不适用于 cl
  • 构造函数中显式关键字的使用

    我试图了解 C 中显式关键字的用法 并查看了这个问题C 中的explicit关键字是什么意思 https stackoverflow com questions 121162 但是 那里列出的示例 实际上是前两个答案 对于用法并不是很清楚
  • C++ 异步线程同时运行

    我是 C 11 中线程的新手 我有两个线程 我想让它们同时启动 我可以想到两种方法 如下 然而 似乎它们都没有按照我的预期工作 他们在启动另一个线程之前启动一个线程 任何提示将不胜感激 另一个问题是我正在研究线程队列 所以我会有两个消费者和
  • 如何配置 WebService 返回 ArrayList 而不是 Array?

    我有一个在 jax ws 上实现的 java Web 服务 此 Web 服务返回用户的通用列表 它运行得很好 Stateless name AdminToolSessionEJB RemoteBinding jndiBinding Admi
  • 暂停下载线程

    我正在用 C 编写一个非常简单的批量下载程序 该程序读取要下载的 URL 的 txt 文件 我已经设置了一个全局线程和委托来更新 GUI 按下 开始 按钮即可创建并启动该线程 我想要做的是有一个 暂停 按钮 使我能够暂停下载 直到点击 恢复
  • 当前的 c++ 工作草案与当前标准有何不同

    通过搜索该标准的 PDF 版本 我最终找到了这个链接C 标准措辞草案 http www open std org jtc1 sc22 wg21 docs papers 2012 n3376 pdf从 2011 年开始 我意识到我可以购买最终
  • C 语言中 =+(等于加)是什么意思?

    我碰到 与标准相反 今天在一些 C 代码中 我不太确定这里发生了什么 我在文档中也找不到它 In ancientC 版本 相当于 它的残余物与最早的恐龙骨头一起被发现 例如 B 引入了广义赋值运算符 使用x y to add y to x
  • 将数据打印到文件

    我已经超载了 lt lt 运算符 使其写入文件并写入控制台 我已经为同一个函数创建了 8 个线程 并且我想输出 hello hi 如果我在无限循环中运行这个线程例程 文件中的o p是 hello hi hello hi hello hi e
  • 如何重置捕获像素的值

    我正在尝试创建一个 C 函数 该函数返回屏幕截图位图中每四个像素的 R G 和 B 值 这是我的代码的一部分 for int ix 4 ix lt 1366 ix ix 4 x x 4 for int iy 3 iy lt 768 iy i
  • 生产代码中的 LRU 实现

    我有一些 C 代码 需要使用 LRU 技术实现缓存替换 目前我知道两种实现LRU缓存替换的方法 每次访问缓存数据时使用时间戳 最后比较替换时的时间戳 使用缓存项的堆栈 如果最近访问过它们 则将它们移动到顶部 因此最后底部将包含 LRU 候选
  • 在 C 中使用 GNU automake 中的解析器

    我是 GNU autotools 的新手 在我的项目中使用了 lex 和 yacc 解析器 将它们作为 makefile am 中的源代码会产生以下错误 配置 in AC CHECK PROGS YACC bison yacc none i
  • 为什么拆箱枚举会产生奇怪的结果?

    考虑以下 Object box 5 int int int box int 5 int nullableInt box as int nullableInt 5 StringComparison enum StringComparison
  • 使用 C# 从 DateTime 获取日期

    愚蠢的问题 给定日期时间中的日期 我知道它是星期二 例如我如何知道它的 tue 2 和 mon 1 等 Thanks 您正在寻找星期几 http msdn microsoft com en us library system datetim

随机推荐