2017-09-25 13 views
3

Je souhaite utiliser un dispatch IO channel pour lire certaines données d'un descripteur de fichier. Après avoir créé le canal, l'étape suivante consiste à appeler read, dont la déclaration est la suivante:Incompatibilité de type dans l'incrustation Swift GCD

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

La documentation pour le paramètre length dit:

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

semble assez facile. Dans mon cas, je voudrais faire juste cela - lire jusqu'à EOF. Je vais passer SIZE_MAX:

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

Le lecteur astucieux a deviné que le compilateur n'aime pas:

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

SIZE_MAX est de type UInt, mais length est de type Int. Le compilateur propose de le fixer:

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

Mais bien sûr, à l'exécution, cela ne fonctionne pas si bien:

fatal error: Not enough bits to represent a signed value

Naturellement, si SIZE_MAX est la plus grande valeur par représentable UInt, puis Int Je ne peux pas le représenter. Après quelques recherches rapides, j'ai trouvé this exact issue on the Swift bug tracker. Comme il ne semble pas encore être traité - et je ne suis pas sûr de ma capacité à y répondre moi-même avec une demande d'extraction - comment puis-je contourner ce problème? Ou est-ce que je manque un moyen de faire ce que je veux? Le document de justification Swift Stdlib covers the explicit decision to import size_t as Int rather than UInt. Il se résume à "moins de conversions de type, et qui a besoin de spécifier des nombres au-dessus de 2^63 de toute façon (désolé, plates-formes 32 bits)." Assez juste, mais cela ne couvre pas les problèmes comme le mien, où l'utilisation de SIZE_MAX fait partie d'une API.

+0

Est-ce que le fait de passer 'longueur: Int (bitPattern: SIZE_MAX)' fonctionne? –

+0

Il pourrait! Il au moins compile et ne plante pas. Honnêtement, je n'ai pas encore trouvé un moyen raisonnable de tester cela.Je ne peux pas créer un flux de données d'une longueur de 2^64 octets, et je n'ai pas une idée précise de la façon dont le 'Int' est transformé en un' size_t' sur l'interface Swift vers C. – ravron

Répondre

2

Utilisez simplement Int.max Si vous êtes sur une plate-forme 64 bits, vous avez toujours la garantie d'atteindre la fin du fichier avant de lire Int.max octets. Sur une plate-forme 32 bits, si votre fichier est très volumineux, vous devrez peut-être émettre plus d'une lecture.

Ensuite, vous devez signaler le problème à Apple. Je ne suis pas sûr si la bibliothèque Dispatch IO appartient à Apple ou au projet Swift Open Source, ou s'il s'agit simplement d'une erreur de documentation.

Mise à jour

Le code source est open source, et l'opération de lecture est juste une simple enveloppe à une fonction C qui prend une size_t pour la longueur.

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

Je ne l'ai pas essayé, mais vous pouvez utiliser presque certainement le modèle binaire ou probablement même -1. Je pense que je voudrais encore aller avec Int.max cependant.

+0

J'ai testé passer Int (bitPattern: SIZE_MAX) 'dans une fonction factice C comme' size_t', et il fonctionne réellement comme prévu, avec cet argument de comparaison égal à 'SIZE_MAX' en C. Je vais accepter cela sur cette base . – ravron