Spec-Zone.ru › C

Неявные преобразования

Когда выражение используется в контексте, где ожидается значение другого типа, может произойти преобразование:

int n = 1L; // expression 1L has type long, int is expected
n = 2.1; // expression 2.1 has type double, int is expected
char* p = malloc(10); // expression malloc(10) has type void*, char* is expected

Преобразования происходят в следующих ситуациях:

Преобразование как при присваивании

  • В операторе присваивания значение правого операнда преобразуется к типу левого операнда без квалификаторов.
  • При скалярной инициализации значение выражения-инициализатора преобразуется к типу инициализируемого объекта без квалификаторов.
  • В выражении вызова функции для функции с прототипом значение каждого выражения-аргумента преобразуется к типу соответствующего параметра без квалификаторов.
  • В операторе возврата значение операнда return преобразуется к объекту с типом возвращаемого значения функции.

Обратите внимание, что фактическое присваивание, помимо преобразования, также удаляет из типов с плавающей точкой избыточный диапазон и точность и запрещает перекрытия; эти характеристики не относятся к преобразованию как при присваивании.

Стандартные продвижения аргументов

В выражении вызова функции, если вызывается

1) функция без прототипа (до C23),
2) функция с переменным числом аргументов, где выражение-аргумент является одним из завершающих аргументов, соответствующих параметру-многоточию.

Каждый аргумент целочисленного типа подвергается целочисленному продвижению, а каждый аргумент типа float неявно преобразуется к типу double.

int add_nums(int count, ...);
int sum = add_nums(2, 'c', true); // add_nums is called with three ints: (2, 99, 1)

Обратите внимание, что в этом контексте floatcomplex и floatimaginary не продвигаются до doublecomplex и doubleimaginary.

(начиная с C99)

Обычные арифметические преобразования

Аргументы следующих арифметических операторов подвергаются неявным преобразованиям, чтобы получить общий вещественный тип , то есть тип, в котором выполняется вычисление:

  • бинарные арифметические операторы *, /, %, +, -,
  • операторы отношения <, >, <=, >=, ==, !=,
  • бинарные побитовые арифметические операторы &, ^, |,
  • условный оператор ?:.
1) Если один операнд имеет десятичный тип с плавающей точкой, другой операнд не должен иметь стандартный тип с плавающей точкой,

комплексный или мнимый тип.

  • Сначала, если тип одного из операндов — _Decimal128, другой операнд преобразуется к _Decimal128.
  • Иначе, если тип одного из операндов — _Decimal64, другой операнд преобразуется к _Decimal64.
  • Иначе, если тип одного из операндов — _Decimal32, другой операнд преобразуется к _Decimal32.
(начиная с C23)
2) Иначе, если один из операндов — longdouble, longdoublecomplex или longdoubleimaginary(начиная с C99), другой операнд неявно преобразуется следующим образом:
  • целочисленный тип или вещественный тип с плавающей точкой — к longdouble
  • комплексный тип — к longdoublecomplex
  • мнимый тип — к longdoubleimaginary
(начиная с C99)
3) Иначе, если один из операндов — double, doublecomplex или doubleimaginary(начиная с C99), другой операнд неявно преобразуется следующим образом:
  • целочисленный тип или вещественный тип с плавающей точкой — к double
  • комплексный тип — к doublecomplex
  • мнимый тип — к doubleimaginary
(начиная с C99)
4) Иначе, если один из операндов — float, floatcomplex или floatimaginary(начиная с C99), другой операнд неявно преобразуется следующим образом:
  • целочисленный тип — к float (единственный возможный вещественный тип — float, он остается без изменений)
  • комплексный тип остается floatcomplex
  • мнимый тип остается floatimaginary
(начиная с C99)
5) В противном случае оба операнда являются целыми числами. Оба операнда подвергаются целочисленному продвижению; затем, после целочисленного продвижения, применяется один из следующих случаев:
  • Если типы одинаковы, этот тип является общим типом.
  • Иначе типы различаются:
    • Если типы имеют одинаковую знаковость (оба знаковые или оба беззнаковые), операнд с типом, имеющим меньший ранг преобразования [1], неявно преобразуется[2] к другому типу.
    • Иначе операнды имеют разную знаковость:
      • Если ранг преобразования беззнакового типа больше или равен рангу знакового типа, операнд со знаковым типом неявно преобразуется к беззнаковому типу.
      • Иначе ранг преобразования беззнакового типа меньше ранга знакового:
        • Если знаковый тип может представлять все значения беззнакового типа, операнд с беззнаковым типом неявно преобразуется к знаковому типу.
        • Иначе оба операнда неявно преобразуются к беззнаковому аналогу типа знакового операнда.
  1. Правила ранжирования см. ниже в разделе «Целочисленные продвижения».
  2. См. ниже раздел «Целочисленные преобразования» в подразделе «Семантика неявных преобразований».
1.f + 20000001; // int is converted to float, giving 20000000.00
                // addition and then rounding to float gives 20000000.00

(char)'a' + 1L; // first, char 'a', which is 97, is promoted to int
                // different types: int and long
                // same signedness: both signed
                // different rank: long is of greater rank than int
                // therefore, int 97 is converted to long 97
                // the result is 97 + 1 = 98 of type signed long

2u - 10; // different types: unsigned int and signed int
         // different signedness
         // same rank
         // therefore, signed int 10 is converted to unsigned int 10
         // since the arithmetic operation is performed for unsigned integers
         // (see “Arithmetic operators” topic), the calculation performed is (2 - 10)
         // modulo (2 raised to n), where n is the number of value bits of unsigned int
         // if unsigned int is 32-bit long and there is no padding bits in its object
         // representation, then the result is (-8) modulo (2 raised to 32) = 4294967288
         // of type unsigned int

5UL - 2ULL; // different types: unsigned long and unsigned long long
            // same signedness
            // different rank: rank of unsigned long long is greater
            // therefore, unsigned long 5 is converted to unsigned long long 5
            // since the arithmetic operation is performed for unsigned integers
            // (see “Arithmetic operators” topic),
            // if unsigned long long is 64-bit long, then
            // the result is (5 - 2) modulo (2 raised to 64) = 3 of type
            // unsigned long long

0UL - 1LL; // different types: unsigned long and signed long long
           // different signedness
           // different rank: rank of signed long long is greater.
           // if ULONG_MAX > LLONG_MAX, then signed long long cannot represent all
           // unsigned long therefore, this is the last case: both operands are converted
           // to unsigned long long unsigned long 0 is converted to unsigned long long 0
           // long long 1 is converted to unsigned long long 1 since the arithmetic
           // operation is performed for unsigned integers
           // (see “Arithmetic operators” topic),
           // if unsigned long long is 64-bit long, then
           // the calculation is (0 - 1) modulo (2 raised to 64)
           // thus, the result is 18446744073709551615 (ULLONG_MAX) of type
           // unsigned long long

Тип результата определяется следующим образом:

  • если оба операнда комплексные, тип результата комплексный;
  • если оба операнда мнимые, тип результата мнимый;
  • если оба операнда вещественные, тип результата вещественный;
  • если два операнда с плавающей точкой принадлежат к разным доменам типов (комплексный и вещественный, комплексный и мнимый или мнимый и вещественный), тип результата комплексный.
double complex z = 1 + 2*I;
double f = 3.0;
z + f; // z remains as-is, f is converted to double, the result is double complex
(начиная с C99)

Как и всегда, результат операции с плавающей точкой может иметь диапазон и точность больше, чем указано его типом (см. FLT_EVAL_METHOD).

Примечание: вещественные и мнимые операнды не преобразуются неявно в комплексные, поскольку для этого потребовались бы дополнительные вычисления, приводящие к нежелательным результатам в некоторых случаях с бесконечностями, NaN и знаковыми нулями. Например, если бы вещественные значения преобразовывались в комплексные, 2.0×(3.0+i∞) вычислялось бы как (2.0+i0.0)×(3.0+i∞) ⇒ (2.0×3.0–0.0×∞) + i(2.0×∞+0.0×3.0) ⇒ NaN+i∞ вместо правильного результата 6.0+i∞. Если бы мнимые значения преобразовывались в комплексные, i2.0×(∞+i3.0) вычислялось бы как (0.0+i2.0) × (∞+i3.0) ⇒ (0.0×∞ – 2.0×3.0) + i(0.0×3.0 + 2.0×∞) ⇒ NaN + i∞ вместо –6.0 + i∞.

(начиная с C99)

Примечание: независимо от обычных арифметических преобразований, в соответствии с правилом «как если бы» вычисление всегда может выполняться в более узком типе, чем предписывают эти правила.

Преобразования значений

Преобразование lvalue

Любое выражение lvalue любого не массивного типа, используемое в любом контексте, кроме следующих:

  • в качестве операнда оператора взятия адреса (если это допускается);
  • в качестве операнда префиксного или постфиксного оператора инкремента или декремента;
  • в качестве левого операнда оператора доступа к члену (точка);
  • в качестве левого операнда операторов присваивания и составного присваивания;
  • в качестве операнда sizeof,

подвергается преобразованию lvalue : тип остается тем же, но теряет квалификаторы const/volatile/restrict и свойства атомарности, если они имеются. Значение остается тем же, но теряет свойства lvalue (его адрес больше нельзя получить).

Если lvalue имеет неполный тип, поведение не определено.

Если lvalue обозначает объект с автоматической длительностью хранения, адрес которого никогда не брался, и этот объект не был инициализирован (не объявлен с инициализатором и до использования ему не присваивалось значение), поведение не определено.

Это преобразование моделирует загрузку значения объекта из его местоположения в памяти.

volatile int n = 1;
int x = n;            // lvalue conversion on n reads the value of n
volatile int* p = &n; // no lvalue conversion: does not read the value of n

Преобразование массива в указатель

Любое выражение lvalue(до C99)выражение(начиная с C99) массивного типа, используемое в любом контексте, кроме следующих:

  • в качестве операнда оператора взятия адреса;
  • в качестве операнда sizeof;
  • в качестве операнда typeof и typeof_unqual (начиная с C23);
  • в качестве строкового литерала, используемого для инициализации массива,

преобразуется в указатель, не являющийся lvalue и указывающий на его первый элемент.

Если массив был объявлен с register, поведение не определено.

Массив, не являющийся lvalue, и любой из его элементовнедоступны(до C99)имеют временную длительность жизни(начиная с C99).

int a[3], b[3][4];
int* p = a;      /* conversion to &a[0] */
int (*q)[4] = b; /* conversion to &b[0] */

struct S
{
    int a[1];
};

struct S f(void)
{
    struct S result = {{0}}; /* {0} since C99 */
    return result;
}

void g(void)
{
    int* p = f().a;    /* error until C99; OK since C99 */
    int n  = f().a[0]; /* error until C99; OK since C99 */
    f().a[0] = 13;     /* error until C99; UB since C99 */
    (void)p, (void)n;
}

int main(void) { return 0; }

Преобразование функции в указатель

Любое выражение, обозначающее функцию, используемое в любом контексте, кроме следующих:

  • в качестве операнда оператора взятия адреса;
  • в качестве операнда sizeof;
  • в качестве операнда typeof и typeof_unqual (начиная с C23),

преобразуется в указатель, не являющийся lvalue и указывающий на функцию, обозначенную выражением.

int f(int);
int (*p)(int) = f; // conversion to &f
(***p)(1); // repeated dereference to f and conversion back to &f

Семантика неявных преобразований

Неявное преобразование, будь то как при присваивании  или обычное арифметическое преобразование , состоит из двух этапов:

1) преобразование значения (если применимо);
2) одно из перечисленных ниже преобразований (если оно может дать целевой тип).

Совместимые типы

Преобразование значения любого типа к любому совместимому типу всегда является пустой операцией и не меняет представление.

uint8_t (*a)[10];         // if uint8_t is a typedef to unsigned char
unsigned char (*b)[] = a; // then these pointer types are compatible

Целочисленные продвижения

Целочисленное продвижение — это неявное преобразование значения любого целочисленного типа с рангом, меньшим или равным рангу типа int, либо битового поля типа _Bool(до C23)bool(начиная с C23), int, signedint, unsignedint, к значению типа int или unsignedint.

Если int может представить весь диапазон значений исходного типа (или диапазон значений исходного битового поля), значение преобразуется к типу int. В противном случае значение преобразуется к unsignedint.

Значение битового поля целочисленного типа с точно заданной разрядностью преобразуется к соответствующему целочисленному типу с точно заданной разрядностью. В остальных случаях целочисленные типы с точно заданной разрядностью не подпадают под правила целочисленного продвижения.

(начиная с C23)

Целочисленные продвижения сохраняют значение, включая знак:

int main(void)
{
    void f(); // old-style function declaration
              // since C23, void f(...) has the same behavior wrt promotions
    char x = 'a'; // integer conversion from int to char
    f(x); // integer promotion from char back to int
}

void f(x) int x; {} // the function expects int

Указанный выше ранг является свойством каждого целочисленного типа и определяется следующим образом:

1) ранги всех знаковых целочисленных типов различны и увеличиваются с повышением точности: ранг signedchar < ранг short < ранг int < ранг longint < ранг longlongint
2) ранги всех знаковых целочисленных типов равны рангам соответствующих беззнаковых целочисленных типов
3) ранг любого стандартного целочисленного типа выше ранга любого расширенного целочисленного типа или целочисленного типа с точно заданной разрядностью(начиная с C23) того же размера (то есть ранг __int64 < ранг longlongint, но ранг longlong < ранг __int128 согласно правилу (1))
4) ранг char равен рангу signedchar и рангу unsignedchar
5) ранг типа _Bool(до C23)bool(начиная с C23) ниже ранга любого другого стандартного целочисленного типа
6) ранг любого перечислимого типа равен рангу его совместимого целочисленного типа
7) ранжирование транзитивно: если ранг T1 < ранга T2 и ранг T2 < ранга T3, то ранг T1 < ранга T3.
8) ранг знакового целочисленного типа с точно заданной разрядностью должен быть выше ранга любого стандартного целочисленного типа с меньшей шириной или любого целочисленного типа с точно заданной разрядностью с меньшей шириной. 9) ранг любого целочисленного типа с точно заданной разрядностью относительно расширенного целочисленного типа той же ширины определяется реализацией. (начиная с C23)
10) любые аспекты относительного ранжирования расширенных целочисленных типов, не указанные выше, определяются реализацией.

Примечание: целочисленные продвижения применяются только

  • как часть обычных арифметических преобразований (см. выше);
  • как часть стандартных продвижений аргументов (см. выше);
  • к операнду унарных арифметических операторов + и -;
  • к операнду унарного побитового оператора ~;
  • к обоим операндам операторов сдвига << и >>.

Логическое преобразование

Значение любого скалярного типа может быть неявно преобразовано к _Bool(до C23)bool(начиная с C23). Значения, которые сравниваются на равенство с целочисленным константным выражением, значение которого равно нулю(до C23)являются нулем (для арифметических типов), нулевым указателем (для типов указателей) или имеют тип nullptr_t(начиная с C23), преобразуются к 0(до C23)false(начиная с C23), все остальные значения преобразуются к 1(до C23)true(начиная с C23).

bool b1 = 0.5;              // b1 == 1 (0.5 converted to int would be zero)
bool b2 = 2.0*_Imaginary_I; // b2 == 1 (but converted to int would be zero)
bool b3 = 0.0 + 3.0*I;      // b3 == 1 (but converted to int would be zero)
bool b4 = 0.0 / 0.0;        // b4 == 1 (NaN does not compare equal to zero)
bool b5 = nullptr;          // b5 == 0 (since C23: nullptr is converted to false)
(начиная с C99)

Целочисленные преобразования

Значение любого целочисленного типа может быть неявно преобразовано к любому другому целочисленному типу. За исключением случаев, рассмотренных выше в разделах о продвижениях и логических преобразованиях, действуют следующие правила:

  • если целевой тип может представить это значение, значение остается неизменным;
  • иначе, если целевой тип беззнаковый, значение 2b, где b — число битов значения в целевом типе, многократно вычитается из исходного значения или прибавляется к нему, пока результат не попадет в диапазон целевого типа. Другими словами, беззнаковые целые числа используют арифметику по модулю.
  • иначе, если целевой тип знаковый, поведение определяется реализацией (в том числе может быть поднят сигнал).
char x = 'a'; // int -> char, result unchanged
unsigned char n = -123456; // target is unsigned, result is 192 (that is, -123456+483*256)
signed char m = 123456;    // target is signed, result is implementation-defined
assert(sizeof(int) > -1);  // assert fails:
                           // operator > requests conversion of -1 to size_t,
                           // target is unsigned, result is SIZE_MAX

Преобразования вещественных значений с плавающей точкой в целые

Конечное значение любого вещественного типа с плавающей точкой может быть неявно преобразовано к любому целочисленному типу. За исключением случаев, рассмотренных выше в разделе о логическом преобразовании, действуют следующие правила:

  • Дробная часть отбрасывается (округление выполняется к нулю).
    • Если полученное значение может быть представлено целевым типом, используется это значение.
    • иначе поведение не определено.
int n = 3.14; // n == 3
int x = 1e10; // undefined behavior for 32-bit int

Значение любого целочисленного типа может быть неявно преобразовано к любому вещественному типу с плавающей точкой.

  • если целевой тип может точно представить значение, оно остается неизменным.
  • если значение представимо, но не может быть представлено точно, результатом становится определяемый реализацией выбор ближайшего большего или ближайшего меньшего значения, хотя при поддержке арифметики IEEE округление выполняется до ближайшего значения. В этом случае не указано, будет ли поднято исключение FE_INEXACT.
  • если значение непредставимо, поведение не определено, хотя при поддержке арифметики IEEE поднимается исключение FE_INVALID, а значение результата не определено.

Результат этого преобразования может иметь диапазон и точность больше, чем указано целевым типом (см. FLT_EVAL_METHOD).

Если при преобразованиях вещественных значений в целые требуется управление FE_INEXACT, можно использовать rint и nearbyint.

double d = 10; // d = 10.00
float f = 20000001; // f = 20000000.00 (FE_INEXACT)
float x = 1 + (long long)FLT_MAX; // undefined behavior

Преобразования вещественных значений с плавающей точкой

Значение любого вещественного типа с плавающей точкой может быть неявно преобразовано к любому другому вещественному типу с плавающей точкой.

  • Если целевой тип может точно представить значение, оно остается неизменным.
  • если значение представимо, но не может быть представлено точно, результатом становится ближайшее большее или ближайшее меньшее значение (другими словами, направление округления определяется реализацией), хотя при поддержке арифметики IEEE округление выполняется до ближайшего значения.
  • если значение непредставимо, поведение не определено.

Результат этого преобразования может иметь диапазон и точность больше, чем указано целевым типом (см. FLT_EVAL_METHOD).

double d = 0.1; // d = 0.1000000000000000055511151231257827021181583404541015625
float f = d;    // f = 0.100000001490116119384765625
float x = 2 * (double)FLT_MAX; // undefined

Преобразования комплексных типов

Значение любого комплексного типа может быть неявно преобразовано к любому другому комплексному типу. Действительная и мнимая части по отдельности преобразуются по правилам для вещественных типов с плавающей точкой.

double complex d = 0.1 + 0.1*I;
float complex f = d; // f is (0.100000001490116119384765625, 0.100000001490116119384765625)

Преобразования мнимых типов

Значение любого мнимого типа может быть неявно преобразовано к любому другому мнимому типу. Мнимая часть преобразуется по правилам для вещественных типов с плавающей точкой.

double imaginary d = 0.1*_Imaginary_I;
float imaginary f = d; // f is 0.100000001490116119384765625*I

Преобразования вещественных и комплексных типов

Значение любого вещественного типа с плавающей точкой может быть неявно преобразовано к любому комплексному типу.

  • Действительная часть результата определяется правилами преобразования вещественных типов с плавающей точкой.
  • Мнимая часть результата равна положительному нулю (или беззнаковому нулю в системах, не поддерживающих IEEE).

Значение любого комплексного типа может быть неявно преобразовано к любому вещественному типу с плавающей точкой.

  • Действительная часть преобразуется по правилам для вещественных типов с плавающей точкой.
  • Мнимая часть отбрасывается.

Примечание: при преобразовании комплексного типа в вещественный NaN в мнимой части не распространяется на вещественный результат.

double complex z = 0.5 + 3*I;
float f = z;  // the imaginary part is discarded, f is set to 0.5
z = f;        // sets z to 0.5 + 0*I

Преобразования вещественных и мнимых типов

Значение любого мнимого типа может быть неявно преобразовано к любому вещественному типу (целочисленному или с плавающей точкой). Результат всегда равен положительному (или беззнаковому) нулю, кроме случая, когда целевой тип — _Bool(до C23)bool(начиная с C23); в этом случае применяются правила логического преобразования.

Значение любого вещественного типа может быть неявно преобразовано к любому мнимому типу. Результат всегда равен положительному мнимому нулю.

double imaginary z = 3*I;
bool b = z;  // Boolean conversion: sets b to true 
float f = z; // Real-imaginary conversion: sets f to 0.0 
z = 3.14;    // Imaginary-real conversion: sets z to 0*_Imaginary_I

Преобразования комплексных и мнимых типов

Значение любого мнимого типа может быть неявно преобразовано к любому комплексному типу.

  • Действительная часть результата равна положительному нулю.
  • Мнимая часть результата преобразуется по правилам для соответствующих вещественных типов.

Значение любого комплексного типа может быть неявно преобразовано к любому мнимому типу.

  • Действительная часть отбрасывается.
  • Мнимая часть результата преобразуется по правилам для соответствующих вещественных типов.
double imaginary z = I * (3*I); // the complex result -3.0+0i loses real part
                                // sets z to 0*_Imaginary_I
(начиная с C99)

Преобразования указателей

Указатель на void может быть неявно преобразован к указателю на объект любого типа и обратно со следующей семантикой:

  • Если указатель на объект преобразуется к указателю на void, а затем обратно, его значение сравнивается как равное исходному указателю.
  • Других гарантий не предоставляется.
int* p = malloc(10 * sizeof(int)); // malloc returns void*

Указатель на тип без квалификаторов может быть неявно преобразован к указателю на квалифицированную версию этого типа (другими словами, можно добавить квалификаторы const, volatile и restrict). Исходный указатель и результат сравниваются как равные.

int n;
const int* p = &n; // &n has type int*

Любое целочисленное константное выражение со значением 0, а также целочисленное выражение-указатель со значением ноль, приведенное к типу void*, могут быть неявно преобразованы к любому типу указателя (как к указателю на объект, так и к указателю на функцию). Результатом является значение нулевого указателя соответствующего типа, которое гарантированно сравнивается как неравное любому ненулевому значению указателя этого типа. Такое целочисленное выражение или выражение void* называется константой нулевого указателя; стандартная библиотека предоставляет определение этой константы в виде макроса NULL.

int* p = 0;
double* q = NULL;

Примечания

Хотя переполнение знакового целого числа в любом арифметическом операторе является неопределенным поведением, переполнение знакового целочисленного типа при целочисленном преобразовании является лишь поведением, не заданным стандартом.

С другой стороны, хотя переполнение беззнакового целого числа в любом арифметическом операторе (и при целочисленном преобразовании) является четко определенной операцией и следует правилам арифметики по модулю, переполнение беззнакового целого числа при преобразовании вещественного значения в целое является неопределенным поведением: значения вещественного типа с плавающей точкой, которые можно преобразовать в беззнаковое целое число, принадлежат открытому интервалу (-1, Unnn_MAX + 1).

unsigned int n = -1.0; // undefined behavior

Преобразования между указателями и целыми числами (за исключением преобразования указателя в _Bool(до C23)bool(с C23) и(с C99)преобразования целочисленного константного выражения со значением ноль в указатель), между указателями на объекты (за исключением случаев, когда исходный или целевой указатель является указателем на void), а также преобразования между указателями на функции (за исключением случаев, когда функции имеют совместимые типы) никогда не выполняются неявно и требуют оператора приведения типа.

Преобразования (неявные или явные) между указателями на функции и указателями на объекты (включая void*) или целыми числами отсутствуют.

Ссылки

  • Стандарт C23 (ISO/IEC 9899:2024):
    • 6.3 Преобразования (с. 44–50)
  • Стандарт C17 (ISO/IEC 9899:2018):
    • 6.3 Преобразования (с. 37–41)
  • Стандарт C11 (ISO/IEC 9899:2011):
    • 6.3 Преобразования (с. 50–56)
  • Стандарт C99 (ISO/IEC 9899:1999):
    • 6.3 Преобразования (с. 42–48)
  • Стандарт C89/C90 (ISO/IEC 9899:1990):
    • 3.2 Преобразования

См. также

Документация по C++ о неявных преобразованиях

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/c/language/conversion

Spec-Zone.ru

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