Tak, kolejność elementów struct w pamięci jest zgodna z ich deklaracją w następującej kolejności: . Szczegóły można znaleźć w The Swift ABI (podkreślenie dodane). Należy jednak pamiętać, korzystanie z „obecnie”, więc ten mogą ulec zmianie w przyszłych wersjach SWIFT:
Fragile Struct i krotka Układ
elemencie krotkach obecnie dzielą ten sam algorytm układ, zwany algorytmem "Universal" w implementacji kompilatora. Algorytm jest następujący:
- start o rozmiarze 0 i dostosowania 1.
- iterację pól , w celu element krotki lub var w deklaracji celu dla elemencie. Dla każdego pola:
- wielkości Update, zaokrąglając w górę do wyrównania pola, czyli zwiększenie go do najmniejszej wartości większej lub równej wielkości i podzielny przez wyrównanie pola.
- Przypisz przesunięcie pola do bieżącej wartości rozmiaru.
- Zaktualizuj rozmiar, dodając rozmiar pola.
- Uaktualnij wyrównanie do maksymalnie wyrównania i wyrównania pola.
- Ostateczny rozmiar i wyrównanie są wielkością i wyrównaniem agregatu. Krokiem tego typu jest końcowy rozmiar zaokrąglony do wyrównania.
Wyściółka/ustawienie jest różne od C:
Należy zauważyć, że różni się od normalnych zasad układu C albo llvm na tym, że wielkość i kroku są różne; mając na uwadze, że układ C wymaga, aby rozmiar osadzonej struktury był wyrównywany do jego wyrównania i aby nic nie było tam układane, układ Swift umożliwia zewnętrznym strukturom rozmieszczenie pól w wewnętrznym obramowaniu klocka wewnętrznego, przy dozwoleniu dopasowania.
Tylko jeśli struktura jest importowane od C, a następnie jest ona gwarantowana mieć takim samym układzie pamięci. Joe Groff od Apple pisze w [swift-users] Mapping C semantics to Swift
Jeżeli zależy od konkretnego układu, należy zdefiniować struct w C i zaimportować go do Swift teraz.
i later in that discussion:
Możesz zostawić struct zdefiniowane w C i zaimportować go do Swift. Swift przestrzega układu C.
przykład:
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
tutaj var d: UInt8
jest rozplanowane w wyściółki ogonowej var sa: A
. Jeżeli określenie samych struktur C
struct CA {
uint8_t a;
uint32_t b;
uint8_t c;
};
struct CB {
struct CA ca;
uint8_t d;
};
i import do Swift następnie
// 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
ponieważ uint8_t d
jest rozplanowane po wyściółki ogonowej struct CA sa
.
jako Swift 3, zarówno size
i stride
powrót tą samą wartość (tym wyściółka struktura) do struktur importowane z C, to znaczy taką samą wartość jak sizeof
w C wrócimy.
Oto prosta funkcja, która pozwala wykazać powyżej (Swift 3)
func showMemory<T>(_ ptr: UnsafePointer<T>) {
let data = Data(bytes: UnsafeRawPointer(ptr), count: MemoryLayout<T>.size)
print(data as NSData)
}
strukturami definiowanymi w 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>
Struktury importowane z 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>
Dlaczego polegasz na położeniu właściwości obiektu? Co chcesz zrobić? – FredericP
Nie chcę nic z tym robić, tylko dlatego, że gdy zaczniesz tworzyć [m | b] iliony małych struktur, różnica zaczyna się sumować, szczególnie na urządzeniach mobilnych. – Ephemera