2017-09-25 2 views
3

Ich möchte eine dispatch IO channel verwenden, um einige Daten aus einem Dateideskriptor zu lesen. Nachdem der Kanal zu schaffen, ist der nächste Schritt read zu nennen, deren Erklärung ist wie folgt:Typ Mismatch in Swift GCD Overlay

func read(offset: off_t, 
    length: Int, 
    queue: DispatchQueue, 
ioHandler: @escaping (Bool, DispatchData?, Int32) -> Void) 

Die Dokumentation für die Parameter length sagt:

The number of bytes to read from the channel. Specify SIZE_MAX to continue reading data until an EOF is reached.

leicht genug zu sein scheint. In meinem Fall würde ich genau das tun - bis EOF lesen. Also werde ich SIZE_MAX passieren:

// `queue` and `handler` defined elsewhere 
channel.read(offset: 0, length: SIZE_MAX, queue: queue, ioHandler: handler) 

Der aufmerksame Leser hat gedacht, dass der Compiler dies nicht mag:

Cannot convert value of type 'UInt' to expected argument type 'Int'

SIZE_MAX ist vom Typ UInt, aber length ist vom Typ Int. Der Compiler bietet es zu beheben:

channel.read(offset: 0, length: Int(SIZE_MAX), queue: queue, ioHandler: handler) 

Aber natürlich zur Laufzeit, wird dies nicht so gut funktionieren:

fatal error: Not enough bits to represent a signed value

Natürlich, wenn SIZE_MAX der größte Wert darstellbaren UInt ist, dann Int kann es nicht darstellen. Nach kurzer Suche fand ich this exact issue on the Swift bug tracker. Da es anscheinend noch nicht angesprochen ist - und ich mich nicht sicher bin, ob ich es mit einer Pull-Anfrage selbst angehen kann - wie kann ich dieses Problem umgehen? Oder fehlt mir eine Möglichkeit, das zu tun, was ich will?


Die Swift Stdlib rationale dokumentiert covers the explicit decision to import size_t as Int rather than UInt. Es läuft auf "weniger Typkonvertierungen hinaus, und wer Zahlen über 2^63 sowieso spezifizieren muss (Entschuldigung, 32-Bit-Plattformen)." Fair genug, aber das gilt nicht für Probleme wie meine, wo die Verwendung von SIZE_MAX Teil einer API ist.

+0

Funktioniert die Weitergabe von 'length: Int (bitPattern: SIZE_MAX)? –

+0

Es könnte! Es kompiliert zumindest und stürzt nicht ab. Ehrlich gesagt, habe ich noch keinen vernünftigen Weg gefunden, das zu testen.Ich kann nicht genau einen Datenstrom erstellen, der 2^64 Bytes lang ist, und ich habe kein festes Handle darüber, wie genau das "Int" über die Swift to C Schnittstelle in ein "size_t" umgewandelt wird. – ravron

Antwort

2

Verwenden Sie einfach Int.max Wenn Sie auf einer 64-Bit-Plattform sind, erreichen Sie immer noch fast das Ende der Datei, bevor Sie Int.max Bytes lesen. Wenn Ihre Datei auf einer 32-Bit-Plattform sehr groß ist, müssen Sie möglicherweise mehr als einen Lesevorgang ausführen.

Dann sollten Sie das Problem an Apple melden. Ich bin mir nicht sicher, ob die Dispatch IO-Bibliothek zu Apple oder zum Swift Open Source-Projekt gehört oder ob es sich lediglich um einen Dokumentationsfehler handelt.

aktualisieren

Der Quellcode ist Open Source, und der Lesevorgang ist nur ein einfaches Wrapper zu einer C-Funktion, die eine size_t für Länge nimmt.

https://github.com/apple/swift-corelibs-libdispatch/blob/master/src/swift/IO.swift

Ich habe nicht versucht, aber man kann mit ziemlicher Sicherheit das Bitmuster verwenden oder wahrscheinlich sogar -1. Ich denke ich würde trotzdem mit Int.max gehen.

+0

Ich überprüfte das Übergeben von 'Int (bitPattern: SIZE_MAX)' in eine Pseudo-C-Funktion als 'size_t', und es funktioniert tatsächlich wie erwartet, wobei dieses Argument gleich'SIZE_MAX' in C ist. Ich akzeptiere dies auf dieser Basis . – ravron