Có, thứ tự của các phần tử cấu trúc trong bộ nhớ là thứ tự của tuyên bố của chúng. Chi tiết có thể được tìm thấy trong The Swift ABI (được thêm vào). Tuy nhiên lưu ý việc sử dụng "hiện", do đó này có thể thay đổi trong một phiên bản tương lai của Swift:
Fragile Struct và tuple Layout
Struct và tuples hiện phần thuật toán bố trí tương tự, lưu ý là thuật toán bố cục "Phổ" trong việc triển khai trình biên dịch. Thuật toán như sau:
- Bắt đầu với một kích thước từ 0 và một liên kết của 1.
- Duyệt qua các lĩnh vực, theo thứ tự nguyên tố cho các bộ, hoặc trong var để khai cho cấu trúc. Đối với mỗi lĩnh vực:
- Cập nhật kích thước bằng cách làm tròn lên đến sự liên kết của lĩnh vực này, có nghĩa là, tăng nó với giá trị tối thiểu lớn hơn hoặc bằng kích thước và chia hết cho sự liên kết của lĩnh vực này.
- Gán độ lệch của trường cho giá trị hiện tại của kích thước.
- Cập nhật kích thước bằng cách thêm kích thước của trường.
- Cập nhật căn chỉnh với mức tối đa là căn chỉnh và căn chỉnh.
- Kích thước và căn chỉnh cuối cùng là kích thước và căn chỉnh của tổng hợp. Bước đi của loại là kích thước cuối cùng được làm tròn lên để căn chỉnh.
Các padding/phù hợp là khác nhau từ C:
Lưu ý rằng điều này khác với quy tắc bố trí bình thường C hoặc LLVM trong đó kích thước và sải chân là khác biệt; trong khi bố cục C yêu cầu kích thước của một cấu trúc nhúng được chèn vào căn chỉnh của nó và không có gì được đặt ở đó, bố cục Swift cho phép cấu trúc bên ngoài bố trí các trường trong phần đuôi của cấu trúc bên trong, cho phép căn chỉnh.
Chỉ khi một struct là nhập khẩu từ C sau đó nó được đảm bảo để có cách bố trí bộ nhớ tương tự. Joe Groff từ Apple viết tại [swift-users] Mapping C semantics to Swift
Nếu bạn phụ thuộc vào bố cục cụ thể, bạn nên xác định cấu trúc trong C và nhập nó vào Swift ngay bây giờ.
và later in that discussion:
Bạn có thể để lại các cấu trúc được định nghĩa trong C và nhập nó vào Swift. Swift sẽ tôn trọng bố cục của C.
Ví dụ:
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
Đây var d: UInt8
được đặt ra trong đệm đuôi của var sa: A
. Nếu bạn xác định các cấu trúc tương tự trong C
struct CA {
uint8_t a;
uint32_t b;
uint8_t c;
};
struct CB {
struct CA ca;
uint8_t d;
};
và nhập nó vào Swift sau đó
// 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
vì uint8_t d
được đặt ra sau khi đệm đuôi của struct CA sa
.
Tính Swift 3, cả hai size
và stride
trả về giá trị cùng (bao gồm struct đệm) cho các cấu trúc nhập khẩu từ C, ví dụ: giá trị tương tự như sizeof
trong C sẽ trở lại.
Đây là một chức năng đơn giản giúp để chứng minh ở trên (Swift 3):
func showMemory<T>(_ ptr: UnsafePointer<T>) {
let data = Data(bytes: UnsafeRawPointer(ptr), count: MemoryLayout<T>.size)
print(data as NSData)
}
Các cấu trúc quy định tại 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ác cấu trúc nhập khẩu từ C:
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>
Tại sao bạn dựa vào vị trí của các thuộc tính của một đối tượng? Bạn muốn làm gì? – FredericP
Tôi không muốn làm bất cứ điều gì với nó đặc biệt, nó chỉ là khi bạn bắt đầu để nhanh chóng [m | b] illions của cấu trúc nhỏ, sự khác biệt bắt đầu để thêm lên, đặc biệt là trên các thiết bị di động. – Ephemera