perlxstypemap
СОДЕРЖАНИЕ
ИМЯ
perlxstypemap - Сопоставление типов C/Perl в Perl XS
ОПИСАНИЕ
Чем больше вы задумываетесь над взаимодействием между двумя языками, тем больше понимаете, что основная часть усилий программиста приходится на преобразование между структурами данных, родными для каждого из языков. Это важнее, чем различия в соглашениях о вызовах, потому что пространство проблем намного больше. Существует гораздо больше способов поместить данные в память, чем способов реализации вызова функции.
Попытка Perl XS решить эту проблему заключается в концепции typemap. На абстрактном уровне typemap в Perl XS — это просто рецепт преобразования из определённой структуры данных Perl в определённую структуру данных C и наоборот. Поскольку могут существовать типы C, которые достаточно похожи друг на друга, чтобы оправдывать преобразование с помощью одной и той же логики, typemap XS представляются уникальным идентификатором, который в данном документе далее называется типом XS. Вы можете сказать компилятору XS, что несколько типов C должны быть сопоставлены с одним typemap XS.
В вашем коде XS, когда вы определяете аргумент с типом C или когда вы используете CODE: и OUTPUT: вместе с типом возвращаемого значения C вашего XSUB, именно механизм сопоставления типов сделает это проще.
Структура typemap
В более практическом плане typemap — это набор фрагментов кода, используемых компилятором xsubpp для сопоставления параметров и значений функций C со значениями Perl. Файл typemap может состоять из трёх разделов, помеченных TYPEMAP, INPUT, и OUTPUT. Непомеченный начальный раздел предполагается как раздел TYPEMAP. Раздел INPUT указывает компилятору, как преобразовать значения Perl в переменные определённых типов C. Раздел OUTPUT указывает компилятору, как преобразовать значения из определённых типов C в значения, которые Perl может понять. Раздел TYPEMAP указывает компилятору, какие фрагменты кода INPUT и OUTPUT следует использовать для сопоставления данного типа C со значением Perl. Разделы TYPEMAP, INPUT, или OUTPUT должны начинаться в первой колонке на отдельной строке и быть заглавными.
Каждый тип раздела может появляться любое количество раз и не обязательно должен появляться вообще. Например, typemap может обычно не содержать разделов INPUT и OUTPUT, если ему нужно только связать дополнительные типы C с основными типами XS, такими как T_PTROBJ. Строки, начинающиеся с символа решётки #, считаются комментариями и игнорируются в разделе TYPEMAP, но считаются значимыми в разделах INPUT и OUTPUT. Пустые строки обычно игнорируются.
Традиционно, typemap необходимо было записывать в отдельный файл, обычно называемый typemap в дистрибутиве CPAN. С версией ExtUtils::ParseXS (компилятор XS) 3.12 или выше, которая поставляется с perl 5.16, typemap также можно встраивать непосредственно в код XS, используя синтаксис типа HERE-doc:
TYPEMAP: <<HERE
...
HERE где HERE можно заменить другими идентификаторами, как и в обычных Perl HERE-doc. Все детали ниже о текстовом формате typemap остаются действительными.
Раздел TYPEMAP должен содержать одну пару типов C и XS на строке, как показано ниже. Пример из файла основных typemap:
TYPEMAP
# all variants of char* is handled by the T_PV typemap
char * T_PV
const char * T_PV
unsigned char * T_PV
... Разделы INPUT и OUTPUT имеют одинаковый формат, то есть каждая неотступленная строка начинает новую карту входных или выходных данных соответственно. Новая карта входных или выходных данных должна начинаться с имени типа XS для сопоставления на отдельной строке, за которым следует код, реализующий её, отступая на следующие строки. Пример:
INPUT
T_PV
$var = ($type)SvPV_nolen($arg)
T_PTR
$var = INT2PTR($type,SvIV($arg)) Мы ещё немного расскажем о значении этих переменных Perl-подобного вида.
Наконец, вот пример полного файла typemap для сопоставления строк C типа char * со скалярами/строками Perl:
TYPEMAP
char * T_PV
INPUT
T_PV
$var = ($type)SvPV_nolen($arg)
OUTPUT
T_PV
sv_setpv((SV*)$arg, $var); Вот более сложный пример: предположим, что вы хотите, чтобы struct netconfig был благословлён в класс Net::Config. Один из способов сделать это — использовать нижние подчёркивания (_) для разделения имён пакетов, как показано ниже:
typedef struct netconfig * Net_Config; И затем предоставить запись typemap T_PTROBJ_SPECIAL, которая сопоставляет нижние подчёркивания с двойными двоеточиями (::), и объявить Net_Config как такого типа:
TYPEMAP
Net_Config T_PTROBJ_SPECIAL
INPUT
T_PTROBJ_SPECIAL
if (sv_derived_from($arg, \"${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\")){
IV tmp = SvIV((SV*)SvRV($arg));
$var = INT2PTR($type, tmp);
}
else
croak(\"$var is not of type ${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\")
OUTPUT
T_PTROBJ_SPECIAL
sv_setref_pv($arg, \"${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\",
(void*)$var); Разделы INPUT и OUTPUT подставляют нижние подчёркивания вместо двойных двоеточий на лету, обеспечивая желаемый эффект. Этот пример демонстрирует некоторые возможности и универсальность средства typemap.
Макрос INT2PTR (определённый в perl.h) преобразует целое число в указатель заданного типа, учитывая возможные различия в размерах целых чисел и указателей. Также существуют макросы PTR2IV, PTR2UV, PTR2NV, для преобразования в обратном направлении, что может быть полезно в разделах OUTPUT.
Роль файла typemap в вашем дистрибутиве
Файл typemap по умолчанию в каталоге lib/ExtUtils исходного кода Perl содержит множество полезных типов, которые могут использоваться расширениями Perl. Некоторые расширения определяют дополнительные typemap, которые хранятся в своих собственных каталогах. Эти дополнительные typemap могут ссылаться на карты INPUT и OUTPUT в основном typemap. Компилятор xsubpp позволит собственному typemap расширения переопределять любые сопоставления, которые находятся в основном typemap. Вместо использования дополнительного файла typemap, typemap могут быть встроены непосредственно в XS с синтаксисом heredoc. Смотрите документацию по ключевому слову XS TYPEMAP:.
Для дистрибутивов CPAN можно предположить, что типы XS, определённые ядром perl, уже доступны. Кроме того, основной typemap имеет значения XS по умолчанию для большого количества типов C. Например, если вы просто возвращаете char * из своего XSUB, в базовом typemap будет этот тип C, связанный с типом XS T_PV. Это означает, что ваша строка C будет скопирована в слот PV (значение указателя) нового скаляра, который будет возвращён из вашего XSUB в Perl.
Если вы разрабатываете дистрибутив CPAN, использующий XS, вы можете добавить свой собственный файл под названием typemap в дистрибутив. Этот файл может содержать typemap, которые либо сопоставляют типы, специфичные для вашего кода, либо переопределяют сопоставления файла основного typemap для распространённых типов C.
Обмен typemap между дистрибутивами CPAN
Начиная с ExtUtils::ParseXS версии 3.13_01 (поставляется с perl 5.16 и выше), обмен кодом typemap между несколькими дистрибутивами CPAN довольно прост. Основная идея — поделиться им как модулем, который предлагает определённый API, и заставить зависимые модули объявить его как требование времени компиляции и импортировать typemap в XS. Примером такого модуля typemap на CPAN является ExtUtils::Typemaps::Basic. Два шага для получения typemap этого модуля в вашем коде:
-
Объявите
ExtUtils::Typemaps::Basicкак зависимость времени компиляции вMakefile.PL(используйтеBUILD_REQUIRES), или в вашемBuild.PL(используйтеbuild_requires). -
Включите следующую строку в раздел XS вашего файла XS: (не разрывайте строку)
INCLUDE_COMMAND: $^X -MExtUtils::Typemaps::Cmd -e "print embeddable_typemap(q{Basic})"
Написание записей typemap
Каждая запись typemap INPUT или OUTPUT — это строка Perl в двойных кавычках, которая будет оцениваться при наличии определённых переменных, чтобы получить окончательный код C для сопоставления определённого типа C.
Это означает, что вы можете встраивать код Perl в свой код typemap (C) с помощью таких конструкций, как ${ perl code that evaluates to scalar reference here }. Распространённый случай использования — это создание сообщений об ошибках, которые ссылаются на истинное имя функции, даже при использовании функции ALIAS XS:
${ $ALIAS ? \q[GvNAME(CvGV(cv))] : \qq[\"$pname\"] } Для многих примеров typemap обратитесь к файлу основного typemap, который можно найти в дереве исходного кода perl в каталоге lib/ExtUtils/typemap.
Переменные Perl, доступные для интерполяции в typemap, следующие:
-
$var — имя входной или выходной переменной, например RETVAL для значений возврата.
-
$type — исходный тип C параметра, любые
:заменены на_. Например, для типаFoo::Bar, $type — этоFoo__Bar -
$ntype — предоставленный тип с
*заменены наPtr. Например, для типаFoo*, $ntype — этоFooPtr -
$arg — элемент стека, из которого параметр вводится или в который выводится, например
ST(0) -
$argoff — смещение аргумента на стеке аргументов. То есть 0 для первого аргумента и т. д.
-
$pname — полное имя XSUB, включая имя
PACKAGE, со всемиPREFIXудалены. Это имя без ALIAS. -
$Package — пакет, указанный последним ключевым словом
PACKAGE -
$ALIAS — неноль, если текущий XSUB имеет какие-либо псевдонимы, объявленные с
ALIAS.
Полный список основных typemap
Каждый тип C представлен записью в файле typemap, отвечающей за преобразование переменных perl (SV, AV, HV, CV и т. д.) в этот тип и из него. В следующих разделах перечислены все типы XS, которые поставляются с perl по умолчанию.
- T_SV
-
Это просто передаёт C-представление переменной Perl (SV*) внутрь и наружу слоя XS. Это можно использовать, если C-код хочет работать напрямую с переменной Perl.
- T_SVREF
-
Используется для передачи и возврата ссылки на SV.
Обратите внимание, что эта карта типов не уменьшает счётчик ссылок при возврате ссылки на SV*. См. также: T_SVREF_REFCOUNT_FIXED
- T_SVREF_FIXED
-
Используется для передачи и возврата ссылки на SV. Это фиксированная разновидность T_SVREF, которая должным образом уменьшает счётчик ссылок при возврате ссылки на SV*. Введена в perl 5.15.4.
- T_AVREF
-
На уровне Perl это ссылка на массив Perl. На уровне C это указатель на AV.
Обратите внимание, что эта карта типов не уменьшает счётчик ссылок при возврате AV*. См. также: T_AVREF_REFCOUNT_FIXED
- T_AVREF_REFCOUNT_FIXED
-
На уровне Perl это ссылка на массив Perl. На уровне C это указатель на AV. Это фиксированная разновидность T_AVREF, которая должным образом уменьшает счётчик ссылок при возврате AV*. Введена в perl 5.15.4.
- T_HVREF
-
На уровне Perl это ссылка на хеш Perl. На уровне C это указатель на HV.
Обратите внимание, что эта карта типов не уменьшает счётчик ссылок при возврате HV*. См. также: T_HVREF_REFCOUNT_FIXED
- T_HVREF_REFCOUNT_FIXED
-
На уровне Perl это ссылка на хеш Perl. На уровне C это указатель на HV. Это фиксированная разновидность T_HVREF, которая должным образом уменьшает счётчик ссылок при возврате HV*. Введена в perl 5.15.4.
- T_CVREF
-
На уровне Perl это ссылка на подпрограмму Perl (например, $sub = sub { 1 };). На уровне C это указатель на CV.
Обратите внимание, что эта карта типов не уменьшает счётчик ссылок при возврате HV*. См. также: T_HVREF_REFCOUNT_FIXED
- T_CVREF_REFCOUNT_FIXED
-
На уровне Perl это ссылка на подпрограмму Perl (например, $sub = sub { 1 };). На уровне C это указатель на CV.
Это фиксированная разновидность T_HVREF, которая должным образом уменьшает счётчик ссылок при возврате HV*. Введена в perl 5.15.4.
- T_SYSRET
-
Карта типов T_SYSRET используется для обработки возвращаемых значений из системных вызовов. Она имеет смысл только при передаче значений из C в Perl (нет понятия передачи значения системного возврата из Perl в C).
Системные вызовы возвращают -1 при ошибке (устанавливая ERRNO с причиной) и (обычно) 0 при успехе. Если возвращаемое значение равно -1, эта карта типов возвращает
undef. Если возвращаемое значение не равно -1, эта карта типов преобразует 0 (Perl false) в "0, но true" (что соответствует Perl true) или возвращает само значение, чтобы указать, что команда выполнена успешно.Модуль POSIX широко использует эту карту.
- T_UV
-
Беззнаковое целое число.
- T_IV
-
Знаковое целое число. Оно приводится к необходимому целочисленному типу при передаче в C и преобразуется в IV при возврате в Perl.
- T_INT
-
Знаковое целое число. Эта карта типов преобразует значение Perl в родной целочисленный тип (тип
intна текущей платформе). При возврате значения в Perl оно обрабатывается так же, как и для T_IV.Её поведение идентично использованию типа
intв XS с T_IV. - T_ENUM
-
Значение перечисления. Используется для передачи компонента перечисления из C. Нет причины передавать значение перечисления в C, поскольку оно хранится как IV внутри Perl.
- T_BOOL
-
Булевый тип. Это можно использовать для передачи значений true и false в C и из C.
- T_U_INT
-
Это для беззнаковых целых чисел. Оно эквивалентно использованию T_UV, но явно приводит переменную к типу
unsigned int. Тип по умолчанию дляunsigned int— T_UV. - T_SHORT
-
Короткие целые числа. Это эквивалентно T_IV, но явно приводит возвращаемое значение к типу
short. Карта типов по умолчанию дляshort— T_IV. - T_U_SHORT
-
Беззнаковые короткие целые числа. Это эквивалентно T_UV, но явно приводит возвращаемое значение к типу
unsigned short. Карта типов по умолчанию дляunsigned short— T_UV.T_U_SHORT используется для типа
U16в стандартной карте типов. - T_LONG
-
Длинные целые числа. Это эквивалентно T_IV, но явно приводит возвращаемое значение к типу
long. Карта типов по умолчанию дляlong— T_IV. - T_U_LONG
-
Беззнаковые длинные целые числа. Это эквивалентно T_UV, но явно приводит возвращаемое значение к типу
unsigned long. Карта типов по умолчанию дляunsigned long— T_UV.T_U_LONG используется для типа
U32в стандартной карте типов. - T_CHAR
-
Однобайтовые символы.
- T_U_CHAR
-
Беззнаковый байт.
- T_FLOAT
-
Число с плавающей точкой. Эта карта типов гарантирует, что будет возвращено значение, приведённое к типу
float. - T_NV
-
Число с плавающей точкой Perl. Похоже на T_IV и T_UV, в том, что возвращаемый тип приводится к запрошенному числовому типу, а не к конкретному типу.
- T_DOUBLE
-
Число с двойной точностью с плавающей точкой. Эта карта типов гарантирует, что будет возвращено значение, приведённое к типу
double. - T_PV
-
Строка (char *).
- T_PTR
-
Адрес памяти (указатель). Обычно связан с типом
void *. - T_PTRREF
-
Аналогично T_PTR, за исключением того, что указатель хранится в скаляре, и ссылка на этот скаляр возвращается вызывающей стороне. Это может использоваться для сокрытия фактического значения указателя от программиста, поскольку оно обычно не требуется напрямую изнутри perl.
Карта типов проверяет, что ссылка на скаляр передаётся из perl в XS.
- T_PTROBJ
-
Аналогично T_PTRREF, за исключением того, что ссылка благословлена в класс. Это позволяет использовать указатель как объект. Чаще всего используется для работы со структурами C. Карта типов проверяет, что объект perl, переданный в процедуру XS, принадлежит к нужному классу (или является частью подкласса).
Указатель благословляется в класс, производный от имени типа указателя, но со всеми '*' в имени, заменёнными на 'Ptr'.
Только для XSUB-файлов
DESTROY, T_PTROBJ оптимизируется до T_PTRREF. Это означает, что проверка класса пропускается. - T_REF_IV_REF
-
ЕЩЁ НЕ ГОТОВО
- T_REF_IV_PTR
-
Аналогично T_PTROBJ, в том, что указатель благословляется в скалярный объект. Разница в том, что когда объект передаётся обратно в XS, он должен быть правильного типа (наследование не поддерживается), в то время как T_PTROBJ поддерживает наследование.
Указатель благословляется в класс, производный от имени типа указателя, но со всеми '*' в имени, заменёнными на 'Ptr'.
Только для XSUB-файлов
DESTROY, T_REF_IV_PTR оптимизируется до T_PTRREF. Это означает, что проверка класса пропускается. - T_PTRDESC
-
ЕЩЁ НЕ ГОТОВО
- T_REFREF
-
Подобно T_PTRREF, за исключением того, что указатель, хранящийся в скаляре, к которому ссылается, де-реферируется и копируется в выходную переменную. Это означает, что T_REFREF относится к T_PTRREF так же, как T_OPAQUE к T_OPAQUEPTR. Всё ясно?
Реализована только часть INPUT (Perl в XSUB), и нет известных пользователей в ядре или на CPAN.
- T_REFOBJ
-
Подобно T_REFREF, за исключением того, что производится жёсткая проверка типа (наследование не поддерживается).
Только для XSUB-файлов
DESTROY, T_REFOBJ оптимизируется до T_REFREF. Это означает, что проверка класса пропускается. - T_OPAQUEPTR
-
Это можно использовать для хранения байтов в строковом компоненте SV. Здесь представление данных не имеет значения для perl, и сами байты просто хранятся в SV. Предполагается, что переменная C является указателем (байты копируются из этого расположения в памяти). Если указатель указывает на нечто, представленное 8 байтами, то эти 8 байтов хранятся в SV (и length() будет сообщать значение 8). Эта запись похожа на T_OPAQUE.
В принципе, команда unpack() может использоваться для преобразования байтов обратно в число (если известно, что базовый тип — число).
Эта запись может использоваться для хранения структуры C (количество байтов для копирования вычисляется с помощью функции C
sizeof) и может использоваться как альтернатива T_PTRREF, без необходимости беспокоиться о утечке памяти (поскольку Perl очистит SV). - T_OPAQUE
-
Это можно использовать для хранения данных из типов, не являющихся указателями, в строковой части SV. Это похоже на T_OPAQUEPTR, за исключением того, что карта типов получает указатель напрямую, а не предполагает, что он предоставляется. Например, если целое число импортируется в Perl с помощью T_OPAQUE вместо T_IV, базовые байты, представляющие целое число, будут храниться в SV, но фактическое значение целого числа недоступно. То есть данные невидимы для perl.
Данные можно получить, используя функцию
unpack, если известен базовый тип байтового потока.T_OPAQUE поддерживает ввод и вывод простых типов. T_OPAQUEPTR может использоваться для передачи этих байтов обратно в C, если допустим указатель.
- Implicit array
-
xsubpp поддерживает специальный синтаксис для возврата упакованных C-массивов в Perl. Если тип возвращаемого значения XS задан как
array(type, nelem)xsubpp скопирует содержимое
nelem * sizeof(type)байтов из RETVAL в SV и добавит его в стек. Это действительно полезно только если количество возвращаемых элементов известно во время компиляции, и вы не против иметь строку байтов в своём SV. Используйте T_ARRAY, чтобы добавлять переменное количество аргументов в стек возврата (однако они не будут упакованы в одну строку).Это похоже на использование T_OPAQUEPTR, но может использоваться для обработки более одного элемента.
- T_PACKED
-
Вызывает пользовательские функции для преобразования. Для
OUTPUT(XSUB в Perl), вызывается функция с именемXS_pack_$ntypeсо скаляром Perl и C переменной для преобразования.$ntype— это нормализованный тип C, который должен быть сопоставлен с Perl. Нормализация означает, что все*заменяются строкойPtr. Возвращаемое значение функции игнорируется.Обратное преобразование для
INPUT(Perl в XSUB), функция с именемXS_unpack_$ntypeвызывается со входным скаляром Perl, а возвращаемое значение приводится к сопоставленному типу C и присваивается выходной C переменной.Пример функции преобразования для типа массива структур
foo_t *может быть:static void XS_pack_foo_tPtr(SV *out, foo_t *in) { dTHX; /* alas, signature does not include pTHX_ */ HV* hash = newHV(); hv_stores(hash, "int_member", newSViv(in->int_member)); hv_stores(hash, "float_member", newSVnv(in->float_member)); /* ... */ /* mortalize as thy stack is not refcounted */ sv_setsv(out, sv_2mortal(newRV_noinc((SV*)hash))); }Преобразование из Perl в C оставлено читателю в качестве упражнения, но прототип будет:
static foo_t * XS_unpack_foo_tPtr(SV *in);Вместо фактической C функции, которая должна получить контекст потока с помощью
dTHX, можно определить макросы с тем же именем и избежать накладных расходов. Также помните о возможной необходимости освободить память, выделеннуюXS_unpack_foo_tPtr. - T_PACKEDARRAY
-
T_PACKEDARRAY похож на T_PACKED. Фактически, тип преобразования
INPUT(Perl в XSUB) идентичен, но тип преобразованияOUTPUTпередает дополнительный аргумент функцииXS_pack_$ntype. Этот третий параметр указывает количество элементов в выводе, чтобы функция могла корректно обрабатывать массивы C. Переменная должна быть объявлена пользователем и иметь имяcount_$ntype, где$ntype— нормализованное имя типа C, как описано выше. Подпись функции для примера выше иfoo_t **:static void XS_pack_foo_tPtrPtr(SV *out, foo_t *in, UV count_foo_tPtrPtr);Тип третьего параметра произволен с точки зрения типа преобразования. Он просто должен соответствовать объявленной переменной.
Конечно, если вы не знаете количество элементов в массиве C
sometype **, внутри вашего XSUB, возвращаемое значениеfoo_t ** XS_unpack_foo_tPtrPtr(...)будет трудно понять. Так как детали полностью зависят от автора XS (пользователя типа преобразования), существует несколько решений, ни одно из которых не является особенно изящным. Наиболее часто встречаемым решением было выделение памяти для N+1 указателей и присваиваниеNULL(N+1) для облегчения итераций.В качестве альтернативы, вероятно, предпочтительнее использовать пользовательское тип преобразования для ваших нужд с самого начала.
- T_DATAUNIT
-
ЕЩЕ НЕ ГОТОВО
- T_CALLBACK
-
ЕЩЕ НЕ ГОТОВО
- T_ARRAY
-
Используется для преобразования списка аргументов Perl в массив C и для добавления содержимого массива C в стек аргументов Perl.
Обычная подпись вызова:
@out = array_func( @in );Любое количество аргументов может быть в списке перед массивом, но входной и выходной массивы должны быть последними элементами в списке.
При передаче списка Perl в C, автор XS должен предоставить функцию (названную по имени типа массива, но с заменой '*' на 'Ptr') для выделения памяти для хранения списка. Должен быть возвращен указатель. Автор XS отвечает за освобождение памяти по выходу из функции. Переменная
ix_$varустанавливается в количество элементов в новом массиве.При возвращении массива C в Perl, автор XS должен предоставить целочисленную переменную, называемую
size_$var, содержащую количество элементов в массиве. Это используется для определения того, сколько элементов должно быть помещено в стек возвращаемых аргументов. Это не требуется на входе, так как Perl знает, сколько аргументов находится в стеке, когда вызывается процедура. Обычно эта переменная называетсяsize_RETVAL.Кроме того, тип каждого элемента определяется типом массива. Если массив использует тип
intArray *, xsubpp автоматически определит, что он содержит переменные типаint, и воспользуется этим описанием типа для копирования каждого элемента. Все теги '*' и 'Array' удаляются из имени для определения подтипа. - T_STDIO
-
Используется для передачи дескрипторов файлов Perl в C и из C, используя структуры
FILE *. - T_INOUT
-
Используется для передачи дескрипторов файлов Perl в C и из C, используя структуры
PerlIO *. Дескриптор файла может использоваться для чтения и записи. Соответствует режиму+<, см. также T_IN и T_OUT.См. perliol для получения дополнительной информации об уровне абстракции ввода-вывода Perl. Perl должен быть скомпилирован с
-Duseperlio.Нет проверки, чтобы гарантировать, что дескриптор файла, переданный из Perl в C, был создан с правильным режимом
open().Подсказка: учебник perlxstut хорошо охватывает типы XS T_INOUT, T_IN и T_OUT.
- T_IN
-
То же, что T_INOUT, но дескриптор файла, возвращаемый из C в Perl, может использоваться только для чтения (режим
<). - T_OUT
-
То же, что T_INOUT, но дескриптор файла, возвращаемый из C в Perl, настроен для использования режима открытия
+>.
© 1993–2020 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.32.0/perlxstypemap