2014-07-09 18 views
40

Để tích hợp với C API trong khi sử dụng Swift, tôi cần sử dụng hàm sizeof. Trong C, điều này thật dễ dàng. Trong Swift, tôi đang ở trong một mê cung các lỗi kiểu.Swift: Cách sử dụng sizeof?

tôi có mã này:

var anInt: Int = 5 
var anIntSize: Int = sizeof(anInt) 

Dòng thứ hai có lỗi " 'NSNumber' không phải là một subtype của 'T.Type'". Tại sao điều này và làm thế nào để sửa chữa nó?

Trả lời

42

Sử dụng sizeof như sau:

let size = sizeof(Int) 

sizeof sử dụng các loại như là tham số.

Nếu bạn muốn kích thước của biến số anInt, bạn có thể chuyển trường dynamicType sang sizeof.

Giống như vậy:

var anInt: Int = 5 
var anIntSize: Int = sizeof(anInt.dynamicType) 

Hoặc đơn giản hơn (chỉ ra bởi user102008):

var anInt: Int = 5 
var anIntSize: Int = sizeofValue(anInt) 
+7

hoặc 'let anIntSize = sizeofValue (anInt)' – user102008

73

Cập nhật cho Swift 3

Hãy cẩn thận rằng MemoryLayout<T>.size nghĩa một cái gì đó khác với sizeof trong C/Obj-C. Bạn có thể đọc chủ đề cũ này https://devforums.apple.com/message/1086617#1086617

Swift sử dụng loại chung để làm rõ rằng số đó được biết lúc biên dịch.

Để tóm tắt, MemoryLayout<Type>.size là khoảng trống cần thiết cho một trường hợp duy nhất trong khi MemoryLayout<Type>.stride là khoảng cách giữa các phần tử kế tiếp trong một mảng tiếp giáp. MemoryLayout<Type>.stride trong Swift giống như sizeof(type) trong C/Obj-C.

Để cung cấp cho một ví dụ cụ thể hơn:

struct Foo { 
    let x: Int 
    let y: Bool 
} 

MemoryLayout<Int>.size  // returns 8 on 64-bit 
MemoryLayout<Bool>.size  // returns 1 
MemoryLayout<Foo>.size  // returns 9 
MemoryLayout<Foo>.stride // returns 16 because of alignment requirements 
MemoryLayout<Foo>.alignment // returns 8, addresses must be multiples of 8 
+0

Wow đây là một thay đổi khá nghiêm trọng so với kích thước được sử dụng để thực hiện. Dẫn đến một số lỗi khi nhóm của chúng tôi chuyển sang Swift 3. –

+0

tôi không thể tìm thấy MemoryLayout trong nhanh chóng 2.3 –

12

Trong Xcode 8 với Swift 3 beta 6 không có chức năng sizeof(). Nhưng nếu bạn muốn, bạn có thể xác định một cho nhu cầu của bạn. Hàm sizeof mới này hoạt động như mong đợi với một mảng. Điều này là không thể với hàm sizein được xây dựng cũ.

let bb: UInt8 = 1 
let dd: Double = 1.23456 

func sizeof <T> (_ : T.Type) -> Int 
{ 
    return (MemoryLayout<T>.size) 
} 

func sizeof <T> (_ : T) -> Int 
{ 
    return (MemoryLayout<T>.size) 
} 

func sizeof <T> (_ value : [T]) -> Int 
{ 
    return (MemoryLayout<T>.size * value.count) 
} 

sizeof(UInt8.self) // 1 
sizeof(Bool.self) // 1 
sizeof(Double.self) // 8 
sizeof(dd)   // 8 
sizeof(bb)   // 1 

var testArray: [Int32] = [1,2,3,4] 
var arrayLength = sizeof(testArray) // 16 

Bạn cần tất cả các phiên bản của hàm sizeof, để lấy kích thước của biến và để có được kích thước chính xác của kiểu dữ liệu và của mảng.

Nếu bạn chỉ xác định hàm thứ hai, thì sizeof (UInt8.self) và sizeof (Bool.self) sẽ dẫn đến "8". Nếu bạn chỉ định nghĩa hai hàm đầu tiên, thì sizeof (testArray) sẽ dẫn đến "8".

+0

Khi tôi nhận được nó, hàm sizeof của bạn trả về kích thước của một đối tượng theo byte. Đúng? Vì vậy, tại sao nó trở lại "24", khi tôi cung cấp cho chuỗi sau đây như một tham số? "11111111111" –

+0

Điều này là do cách thức, chuỗi động được giải mã trong Swift Unicode –

+0

Trong khi điều này sẽ làm việc cho các loại được xây dựng, tôi nghĩ rằng phương pháp mảng sizeof có giá trị giới hạn. Xem kích thước so với bước thảo luận ở trên. Một mảng các cấu trúc tùy ý thường có các yêu cầu liên kết đặc biệt sẽ làm cho số lượng byte tiếp giáp thực sự được lưu lớn hơn. –

11

Swift 3 hiện có MemoryLayout.size(ofValue:) có thể tra cứu kích thước động.

Sử dụng chức năng chung mà lần lượt sử dụng MemoryLayout<Type> sẽ có kết quả không mong muốn nếu bạn, ví dụ: vượt qua nó một tham chiếu của loại giao thức. Điều này là bởi vì - theo như tôi biết - trình biên dịch sau đó có tất cả các thông tin kiểu mà nó cần để điền vào các giá trị tại thời gian biên dịch, mà không rõ ràng khi nhìn vào cuộc gọi hàm.

2

Swift 4

Từ Xcode 9 trở đi có bây giờ là một tài sản được gọi .bitWidth, điều này cung cấp một cách khác để viết sizeof: chức năng cho trường và các loại nguyên:

func sizeof<T:FixedWidthInteger>(_ int:T) -> Int { 
    return int.bitWidth/UInt8.bitWidth 
} 

func sizeof<T:FixedWidthInteger>(_ intType:T.Type) -> Int { 
    return intType.bitWidth/UInt8.bitWidth 
} 

sizeof(UInt16.self) // 2 
sizeof(20) // 8 

Nhưng nó sẽ làm cho hơn ý nghĩa cho sự nhất quán để thay thế sizeof: bằng .byteWidth:

extension FixedWidthInteger { 
    var byteWidth:Int { 
     return self.bitWidth/UInt8.bitWidth 
    } 
    static var byteWidth:Int { 
     return Self.bitWidth/UInt8.bitWidth 
    } 
} 

1.byteWidth // 8 
UInt32.byteWidth // 4 

Thật dễ dàng để xem tại sao sizeof: được cho là mơ hồ nhưng tôi không chắc chắn rằng chôn nó trong MemoryLayout là điều đúng đắn để làm. Xem lý do đằng sau sự dịch chuyển của sizeof: thành MemoryLayouthere.

Các vấn đề liên quan