Swift是否保证类和结构中字段的存储顺序?

前端之家收集整理的这篇文章主要介绍了Swift是否保证类和结构中字段的存储顺序?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在C中,您在结构中定义字段的顺序是它们将在内存中实例化的顺序.考虑到内存对齐,下面的结构在内存中的大小为8字节,如图所示,但如果字段反转则只有6个字节,因为不需要任何对齐填充.
struct s {
    int32_t a;
    /* 2 bytes of padding to align a 64 bit integer */
    int64_t b;
}

这种排序保证存在于C结构,C类(和结构)和Objective-C类中.

对于Swift类和结构中的字段,存储顺序是否同样有保证?或者(鉴于该语言不支持与列出的其他语言相同的指针),编译器是否在编译时为您重新安排它们?

是的,内存中struct元素的顺序是
他们的声明.细节可以找到
The Swift ABI
(重点补充).但请注意使用“当前”,所以这个
可能会在未来的Swift版本中发生变化:

Fragile Struct and Tuple Layout

Structs and tuples currently share the same layout algorithm,noted as the “Universal” layout algorithm in the compiler implementation. The algorithm is as follows:

  • Start with a size of 0 and an alignment of 1.
  • Iterate through the
    fields,in element order for tuples,or in var declaration order for
    structs. For each field:
    • Update size by rounding up to the alignment
      of the field,that is,increasing it to the least value greater or
      equal to size and evenly divisible by the alignment of the field.
    • Assign the offset of the field to the current value of size.
    • Update
      size by adding the size of the field.
    • Update alignment to the max of
      alignment and the alignment of the field.
  • The final size and alignment
    are the size and alignment of the aggregate. The stride of the type is
    the final size rounded up to alignment.

填充/对齐与C不同:

Note that this differs from C or LLVM’s normal layout rules in that size and stride are distinct; whereas C layout requires that an embedded struct’s size be padded out to its alignment and that nothing be laid out there,Swift layout allows an outer struct to lay out fields in the inner struct’s tail padding,alignment permitting.

只有从C导入结构,才能保证具有
相同的内存布局.来自Apple的Joe Groff写道
[swift-users] Mapping C semantics to Swift

If you depend on a specific layout,you should define the struct in C and import it into Swift for now.

later in that discussion

You can leave the struct defined in C and import it into Swift. Swift will respect C’s layout.

例:

struct A {
    var a: UInt8 = 0
    var b: UInt32 = 0
    var c: UInt8 = 0
}

struct B {
    var sa: A
    var d: UInt8 = 0
}

// Swift 2:
print(sizeof(A),strideof(A)) // 9,12
print(sizeof(B),strideof(B)) // 10,12

// Swift 3:
print(MemoryLayout<A>.size,MemoryLayout<A>.stride) // 9,12
print(MemoryLayout<B>.size,MemoryLayout<B>.stride) // 10,12

这里var d:UInt8在var sa的尾部填充中布局:A.
如果在C中定义相同的结构

struct  CA {
    uint8_t a;
    uint32_t b;
    uint8_t c;
};

struct CB {
    struct CA ca;
    uint8_t d;
};

然后将其导入Swift

// Swift 2:
print(sizeof(CA),strideof(CA)) // 9,12
print(sizeof(CB),strideof(CB)) // 13,16

// Swift 3:
print(MemoryLayout<CA>.size,MemoryLayout<CA>.stride) // 12,12
print(MemoryLayout<CB>.size,MemoryLayout<CB>.stride) // 16,16

因为uint8_t d是在结构CA sa的尾部填充之后布局的.

从Swift 3开始,尺寸和步幅都返回相同的值
从C导入的结构(包括struct padding),
即与C中的sizeof相同的值将返回.

这是一个简单的函数,有助于演示上面的内容(Swift 3):

func showMemory<T>(_ ptr: UnsafePointer<T>) {
    let data = Data(bytes: UnsafeRawPointer(ptr),count: MemoryLayout<T>.size)
    print(data as NSData)
}

Swift中定义的结构:

var a = A(a: 0xaa,b: 0xbbbbbbbb,c: 0xcc)
showMemory(&a)    // <aa000000 bbbbbbbb cc>

var b = B(sa: a,d: 0xdd)
showMemory(&b)    // <aa000000 bbbbbbbb ccdd>

从C导入的结构:

var ca = CA(a: 0xaa,c: 0xcc)
showMemory(&ca)   // <aa000000 bbbbbbbb cc000000>

var cb = CB(ca: ca,d: 0xdd)
showMemory(&cb)   // <aa000000 bbbbbbbb cc000000 dd000000>
原文链接:https://www.f2er.com/swift/320229.html

猜你在找的Swift相关文章