Swift как язык C REPL

Системные программисты, которые часто переключаются между операционными системами, страдают амнезией POSIX. Это когда вы знаете, какую функцию POSIX использовать, но забываете о некоторых крайних случаях, кодах возврата или граничных условиях. Какие флаги состояния по умолчанию F_GETFL для файлового дескриптора, открытого с O_NONBLOCK? Что fcntl(fd, F_SETSIZE) будет делать с «/ dev / null» в macOS?

Оказывается, если у вас установлен Xcode, swift CLI можно использовать как забавный REPL на языке C.

Запустите swift CLI из терминала. Чтобы Swift REPL мог использовать многие стандартные функции POSIX, вам также необходимо import Foundation.

Теперь мы можем запускать функции C. Вот open(2):

При вызове open("/dev/null", ...) возвращается 3, которое является ожидаемым возвращаемым значением. Возвращаемое значение (зеленое) имеет префикс типа возвращаемого значения Int32. Int32 Swift (также называемый CInt) соответствует типу int C, который предсказуемо является 32-битным на платформах LP64. В конце концов, можно ожидать, что Int тип Swift будет 64-битным, поэтому Int отличается от CInt.

Давайте воспользуемся Swift let, чтобы зафиксировать возвращаемое значение:

А теперь займемся кое-чем интересным. Давайте восстановим путь к файлу по его файловому дескриптору. К сожалению, это будет немного увлекательно и тяжело. Вот что нужно вырезать и вставить, следуя инструкциям:

import Foundation
let fd = open("/dev/null", O_RDONLY)
var buf = [UInt8](repeating: 0, count: .init(PATH_MAX))
buf.withUnsafeMutableBytes { ptr in
    fcntl(fd, F_GETPATH, ptr.baseAddress!)
}
String(cString: buf)

После ввода последней строки (String(cString: buf)) мы возвращаем представление значения String Swift, содержащего путь к файлу:

Думаю, я просто отговорил вас от использования Swift в качестве C REPL со всей этой withUnsafeMadness сложностью. Давайте попробуем что-нибудь попроще, не требующее никакого управления буфером. Давайте попробуем изменить размер /dev/null файла и посмотрим, что не получится:

Как видите, это выглядит намного более управляемым, и мы даже восстановили печатаемое сообщение об ошибке, соответствующее ошибке fcntl.

В качестве последнего примера давайте посмотрим, как получить размер структуры dirent с помощью Swift. MemoryLayout можно использовать как замену sizeof C.

Ну вот и все. Swift REPL можно использовать для тестирования стандартных функций C, проверки значений констант POSIX (и некоторых #defines) и размеров структур. Может быть удобно или несколько неприятно вызывать определенные вещи, и иногда вам может потребоваться знать больше Swift, чем вы хотели. Но это работает и делает мой день немного проще как на macOS, так и на Linux.