2016-09-03 12 views
6

C, bir yapıda alanları tanımladığınız sıra, bellekte örneklenecekleri sıradır. Bellek hizalaması göz önünde bulundurulduğunda, aşağıdaki yapı, gösterildiği gibi bellekte 8 baytlık bir boyuta sahip olacak, ancak herhangi bir hizalama yastığı olması gerekmediğinden, alanların tersine çevrilmesi durumunda sadece 6 bayt olacaktır.Swift, sınıflar ve yapılardaki alanların depolama sırasını garanti ediyor mu?

struct s { 
    int32_t a; 
    /* 2 bytes of padding to align a 64 bit integer */ 
    int64_t b; 
} 

Bu sıralama garanti C yapılar içinde mevcut olan, C++ sınıflarının (ve yapılar) ve amaç-Cı sınıfları.

depolama sırası benzer Swift sınıflar ve yapılar alanlar için garantisi var mı? Ya da (dil, listelenen diğerleriyle aynı şekilde işaretçileri desteklemediğinden) derleyici derleme zamanında bunları sizin için en iyi şekilde yeniden düzenler mi?

+0

Neden bir nesnenin özelliklerinin konumuna güveniyorsunuz? Ne yapmak istersin? – FredericP

+0

Onunla özellikle bir şey yapmak istemiyorum, sadece küçük yapılardaki [m | b] illionlarını başlatmaya başladığınızda, özellikle mobil cihazlarda fark yaratmaya başlar. – Ephemera

cevap

12

Evet, bellekte yapı öğelerinin sırası bildirimleridir. Detaylar 'da (vurgu eklenmiştir) bulunabilir. "Şu anda" nin ancak kullanımına dikkat, bu nedenle bu Swift gelecekteki bir sürümde değişebilir:

Kırılgan Struct ve kayıt düzeni Düzeni

Yapılar ve küpe halen pay aynı düzen algoritma, derleyici uygulamasında "Evrensel" düzen algoritması olarak not edildi. yöntem aşağıdaki gibi olduğu: yapılar için var bildirimi için 0 olarak bir boyut ve küpe element amacıyla alanları üzerinden 1.

  • yineleme bir hizalama, veya ile

    • başlayın. alanın hizalanmasıyla boyutuna eşit ve düzgün bir şekilde bölünebilir az değeri büyük veya için artan yani, hizalama alanının kadar yuvarlama
      • Güncelleme boyutu: her bir alan için.
      • Alanın uzaklığını geçerli boyut olarak atayın.
      • Alanın boyutunu ekleyerek boyutu güncelleştirin.
      • Hizalamayı hizalamayı diziliminin hizalanması ve alanın hizalanması.
    • Son boyut ve hizalama topluluğun boyutu ve hizalamasıdır. Yazının adımı olup son boyut hizalamaya yuvarlanır.
  • doldurma/hizalama C farklıdır: bu, boyut ve içinde adım C veya LLVM normal düzeni kurallardan farklıdır farklı olduğunu

    Not; C düzeni, gömülü bir yapının boyutunun hizalanmasına kadar doldurulmasını ve orada hiçbir şeyin yerleştirilmemesini gerektirir, Swift düzeni, dış yapının iç yapının kuyruk yastığı, hizalama iznindeki alanları yerleştirmesini sağlar. Bir yapı sonra C'den ithal o aynı bellek düzeni olduğu garanti edilir işlemiyse

    . Apple Joe Groff belirli bir düzen bağlı ise, C yapı tanımlamak ve şimdilik Swift içe olmalıdır [swift-users] Mapping C semantics to Swift

    de yazıyor.

    ve later in that discussion:

    Sen C tanımlanan yapı bırakıp Swift aktarabilirsiniz. Swift, C'nin düzenine saygı gösterecektir.

    Örnek: Aşağıda

    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: UInt8var sa: A kuyruk padding dışarı koydu. Eğer C

    struct CA { 
        uint8_t a; 
        uint32_t b; 
        uint8_t c; 
    }; 
    
    struct CB { 
        struct CA ca; 
        uint8_t d; 
    }; 
    

    aynı yapılarını tanımlamak ve uint8_t dstruct CA sa kuyruk dolgu sonra dışarı koydu

    // 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 
    

    çünkü o Swift aktarın edin. Swift 3 itibarıyla

    , hem size ve stride yapılar C ithal , için aynı değeri ( yapı dolgu içeren ) geri, yani C sizeof aynı dönüş değeri olacaktır.C ithal

    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> 
    

    yapıları:

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

    yapılar Swift tanımlanan:

    var ca = CA(a: 0xaa, b: 0xbbbbbbbb, c: 0xcc) 
    showMemory(&ca) // <aa000000 bbbbbbbb cc000000> 
    
    var cb = CB(ca: ca, d: 0xdd) 
    showMemory(&cb) // <aa000000 bbbbbbbb cc000000 dd000000> 
    
    Burada

    üzerinde göstermek için yardımcı olan basit bir fonksiyonu (Swift 3) olduğu
    +1

    Çok kapsamlı, çok teşekkür ederim! – Ephemera

    1

    Siparişin garanti edildiği anlaşılıyor.

    aşağıdaki yapı göz önüne alındığında:

    struct s { 
        var a: UInt32 
        var c: UInt8 
        var b: UInt64 
    } 
    
    sizeof(s) // 16 
    

    Hizalama hala oluyor. Orada c ve b arasında kayıp 8 bit var.

    struct s { 
        var a: UInt32 
        var b: UInt64 
        var c: UInt8 
    } 
    
    sizeof(s) // 17 
    

    Bu davranış sizden bahsedilen diğer dilleri maçları inanıyoruz: bu bit sonunda tutturdu c & b ya da sadece arasındaki aslında olup olmadığını biz yeniden düzenlemek kadar Tabii

    , bu ... net değil senin sorun.

    +0

    "Kaybolan 8 bit var ..." Bence 3 bayt demek istiyorsun. – RenniePet

    İlgili konular