generics - 为什么 F# 泛型结构有额外的 __dummy 字段?

标签 generics compiler-construction struct f# sizeof

使用 F# Interactive,您可以验证以下大小:

// sizeof<A> = 4 bytes
type A (i: int) = struct end

// sizeof<B<int>> = 8 bytes (use any type parameter)
type B<'T> (i: int) = struct end

额外大小的原因似乎是存在整数 __dummy一般情况下的字段。再次使用 F# Interactive,您可以使用 typeof 看到这一点:

  • typeof<A>显示DeclaredFields = [|Int32 i|]
  • typeof<B<int>>显示DeclaredFields = [|Int32 i; Int32 __dummy|]

我不明白为什么会这样 __dummy已添加字段。

我认为负责添加它的代码在这里:

https://github.com/fsharp/FSharp.Compiler.Service/blob/master/src/fsharp/ilxgen.fs

Line 6377显示此:

if requiresExtraField then 
    yield mkILInstanceField("__dummy",cenv.g.ilg.typ_int32,None,ILMemberAccess.Assembly) ]

Line 6290是哪里requiresExtraField定义为:

let requiresExtraField = 
    let isEmptyStruct = 
        (match ilTypeDefKind with ILTypeDefKind.ValueType -> true | _ -> false) &&
        // All structs are sequential by default 
        // Structs with no instance fields get size 1, pack 0
        tycon.AllFieldsAsList |> List.exists (fun f -> not f.IsStatic)

    isEmptyStruct && cenv.opts.workAroundReflectionEmitBugs && not tycon.TyparsNoRange.IsEmpty

我假设isEmptyStruct应该意味着该结构没有任何实例字段。但是编写的代码正在测试结构是否有任何实例字段,对于大多数结构(包括我的结构)来说,这都是正确的。我认为最终测试的最后一部分是是否有泛型类型参数。所以requiresExtraFieldfalse对于 type A (非通用)和 true对于 type B (通用类型)。

这是编译器错误还是代码正确?如果正确的话,那么这个__dummy的目的是什么? field ?有什么办法可以避免它吗?

作为另一项测试,我删除了唯一的实例字段,毫不奇怪,我得到了以下大小,显示 __dummy不再添加字段:

// sizeof<AA> = 1
type AA = struct end

// sizeof<BB<int>> = 1
type BB<'T> = struct end

我想要使用值类型而不是引用类型的原因是,我将在数据结构中存储大量这些对象,而不仅仅是传递它们。

最佳答案

@jyoung 在我的原始帖子下面的评论中给出了解释。

requiresExtraField的最后一行还测试 cenv.opts.workAroundReflectionEmitBugs 。该标志似乎是在 fscopts.fs 中设置的。代码行是:

workAroundReflectionEmitBugs=tcConfig.isInteractive; // REVIEW: is this still required?

所以额外的问题__dummy字段仅出现在 F# Interactive 中。

关于generics - 为什么 F# 泛型结构有额外的 __dummy 字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25848604/

相关文章:

generics - Guice 类型 Kotlin 中的字面量

c# - 如何使用 System.Reflection.Emit 从 T 创建派生类型

c++ - 代码在 Linux g++ 中无法按预期工作?

c - 结构指针在堆中拥有内存,但是在通过使指针指向其基地址然后打印其大小时出现段错误?

c - 我的程序没有将输入数据存储到 C 中的结构中

c - 在哪里可以找到 -> 解引用运算符的源代码?

java - 具有相同基类的泛型

c# - 如何在不知道 T 范围的情况下传递 Func<T>?

c++ - 我们是否应该在 C++ 中更喜欢临时变量而不是用户定义的变量

c++ - vs2010 C4353 为什么这不是错误