Spec-Zone.ru › Perl 5.32

perlxstypemap

СОДЕРЖАНИЕ

  • ИМЯ
  • ОПИСАНИЕ
    • Структура typemap
    • Роль файла typemap в вашем дистрибутиве
    • Обмен typemap между дистрибутивами CPAN
    • Написание записей typemap
    • Полный список основных typemap

ИМЯ

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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API