Какой размер & ldquo; int & rdquo; в документации Microsoft относительно PInvoke? [Дубликат]

Просто для удовольствия я играл с представлением поплавков, следуя определениям из стандарта C99, и я написал код ниже.

Код печатает двоичное представление поплавков в 3 отдельных группах

SIGN EXPONENT FRACTION

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

Поэтому, когда вы пишете float x = 999... компилятор преобразует это число в битовое представление, напечатанное функцией xx, так что сумма, напечатанная функцией yy, будет равна заданному числу.

В действительности эта сумма является только приближение. Для числа 999,999,999 компилятор будет вставлять в бит представление float число 1,000,000,000

После кода я присоединяю консольный сеанс, в котором я вычисляю сумму терминов для обеих констант (минус PI и 999999999) который действительно существует в аппаратном обеспечении, вставленном там компилятором.

#include <stdio.h>
#include <limits.h>

void
xx(float *x)
{
    unsigned char i = sizeof(*x)*CHAR_BIT-1;
    do {
        switch (i) {
        case 31:
             printf("sign:");
             break;
        case 30:
             printf("exponent:");
             break;
        case 23:
             printf("fraction:");
             break;

        }
        char b=(*(unsigned long long*)x&((unsigned long long)1<<i))!=0;
        printf("%d ", b);
    } while (i--);
    printf("\n");
}

void
yy(float a)
{
    int sign=!(*(unsigned long long*)&a&((unsigned long long)1<<31));
    int fraction = ((1<<23)-1)&(*(int*)&a);
    int exponent = (255&((*(int*)&a)>>23))-127;

    printf(sign?"positive" " ( 1+":"negative" " ( 1+");
    unsigned int i = 1<<22;
    unsigned int j = 1;
    do {
        char b=(fraction&i)!=0;
        b&&(printf("1/(%d) %c", 1<<j, (fraction&(i-1))?'+':')' ), 0);
    } while (j++, i>>=1);

    printf("*2^%d", exponent);
    printf("\n");
}

void
main()
{
    float x=-3.14;
    float y=999999999;
    printf("%lu\n", sizeof(x));
    xx(&x);
    xx(&y);
    yy(x);
    yy(y);
}

Вот сеанс консоли, в котором я вычисляю реальное значение float, которое существует в аппаратном обеспечении. Я использовал bc для печати суммы терминов, выводимых основной программой. Можно вставить эту сумму в python repl или что-то подобное.

-- .../terra1/stub
@ qemacs f.c
-- .../terra1/stub
@ gcc f.c
-- .../terra1/stub
@ ./a.out
sign:1 exponent:1 0 0 0 0 0 0 fraction:0 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 1 0 0 0 0 1 1
sign:0 exponent:1 0 0 1 1 1 0 fraction:0 1 1 0 1 1 1 0 0 1 1 0 1 0 1 1 0 0 1 0 1 0 0 0
negative ( 1+1/(2) +1/(16) +1/(256) +1/(512) +1/(1024) +1/(2048) +1/(8192) +1/(32768) +1/(65536) +1/(131072) +1/(4194304) +1/(8388608) )*2^1
positive ( 1+1/(2) +1/(4) +1/(16) +1/(32) +1/(64) +1/(512) +1/(1024) +1/(4096) +1/(16384) +1/(32768) +1/(262144) +1/(1048576) )*2^29
-- .../terra1/stub
@ bc
scale=15
( 1+1/(2) +1/(4) +1/(16) +1/(32) +1/(64) +1/(512) +1/(1024) +1/(4096) +1/(16384) +1/(32768) +1/(262144) +1/(1048576) )*2^29
999999999.999999446351872

Вот и все. Фактически значение 999999999

999999999.999999446351872

Вы также можете проверить с помощью bc, что -3.14 также возмущено. Не забудьте установить коэффициент scale в bc.

Отображаемая сумма - это то, что внутри аппаратного обеспечения. Значение, которое вы получаете, вычисляя его, зависит от установленного вами масштаба. Я установил коэффициент scale равным 15. Математически, с бесконечной точностью, кажется, что это 1 000 000 000.

631
задан Jonathan Leffler 6 May 2016 в 18:09
поделиться

18 ответов

32
ответ дан Brian Neal 26 August 2018 в 21:43
поделиться

Как отвечали другие, «стандарты» оставляют большинство деталей «реализацией» и указывают только, что тип «char» находится в «char_bis» шириной и что «char & lt; = short & lt; = int & lt; = long & lt; = long long "(float и double в значительной степени соответствуют стандарту IEEE с плавающей запятой, а long double обычно является таким же, как double, но может быть больше для более современных реализаций).

Часть причин не очень точных и точных значений заключается в том, что такие языки, как C / C ++, были переносимы на большое количество аппаратных платформ - включая компьютерные системы, в которых может быть размер слова «char» 4-битные или 7-битные или даже некоторые значения, отличные от компьютеров «8- / 16- / 32- / 64-бит», которым подвергается средний пользователь домашнего компьютера. (Размер слова здесь означает, сколько битов в ширину система работает нормально - Опять же, это не всегда 8 бит, как могут ожидать пользователи домашних компьютеров.)

Если вам действительно нужен объект (в смысле из серии бит, представляющих интегральное значение) определенного количества бит, большинство компиляторов имеют некоторый способ указания этого; Но, как правило, он не переносится даже между компиляторами, производимыми компанией ame, но для разных платформ. Некоторые стандарты и методы (особенно limits.h и т. П.) Достаточно распространены, что большинство компиляторов будут иметь поддержку для определения типа наилучшего соответствия для определенного диапазона значений, но не для количества используемых битов. (То есть, если вы знаете, что вам нужно хранить значения от 0 до 127, вы можете определить, что ваш компилятор поддерживает 8-битный тип «int8», который будет достаточно большим, чтобы удерживать весь желаемый диапазон, но не что-то вроде «int7», который был бы точным совпадением для 7-битов.)

Примечание. Многие исходные пакеты Un * x используют сценарий «./configure», который будет определять возможности компилятора / системы и выводит подходящий Makefile и config.h. Вы можете изучить некоторые из этих сценариев, чтобы увидеть, как они работают, и как они исследуют возможности компилятора / системы и следуют за ними.

2
ответ дан C. M. 26 August 2018 в 21:43
поделиться

Я замечаю, что все остальные ответы здесь сосредоточены почти исключительно на интегральных типах, в то время как вопросник также задал вопрос о плавающих точках.

Я не думаю, что это требует стандарт C ++, но компиляторы для наиболее распространенные платформы в наши дни обычно следуют стандарту IEEE754 для их чисел с плавающей запятой. Этот стандарт указывает четыре типа двоичной с плавающей запятой (а также некоторые форматы BCD, которых я никогда не видел в компиляторах на C ++):

  • Половинная точность (двоичная16) - 11-разрядная значащий, диапазон экспоненты от -14 до 15
  • Одиночная точность (binary32) - 24-разрядная значимая величина, диапазон экспоненциального диапазона от -126 до 127
  • Двойная точность (двоичная -64) - 53-разрядная значимость, диапазон экспоненциального диапазона от -1022 до 1023
  • Четырехчетная точность (binary128) - 113-бит значительная, диапазон экспоненциального диапазона -16382 до 16383

Как это отображается на типы C ++, затем ? Обычно float использует одинарную точность; таким образом, sizeof(float) = 4. Затем double использует двойную точность (я полагаю, что это источник имени double), а long double может быть двойной или четырехкратной точностью (это четверка в моей системе, но в 32-битных системах она может быть двойной) , Я не знаю каких-либо компиляторов, которые предлагают плавающие точки с половинной точностью.

Таким образом, это обычное:

  • sizeof(float) = 4
  • sizeof(double) = 8
  • sizeof(long double) = 8 или 16
0
ответ дан celticminstrel 26 August 2018 в 21:43
поделиться

В стандарте C ++ не указывается размер интегральных типов в байтах, но он указывает минимальные диапазоны, которые они должны удержать. Вы можете вывести минимальный размер в битах из требуемого диапазона. Вы можете вывести минимальный размер в байтах из этого и значение макроса CHAR_BIT, которое определяет количество бит в байте (во всех, кроме самых неясных платформах, это 8, и оно не может будет меньше 8).

Еще одно ограничение для char заключается в том, что его размер всегда равен 1 байту или CHAR_BIT битам (отсюда и название).

Минимальные диапазоны , требуемый стандартом (стр. 22):

и диапазоны типов данных на MSDN :

  1. signed char : От -127 до 127 (обратите внимание, не от -128 до 127, это предполагает платформы с 1-м дополнением и знаками и знаками)
  2. unsigned char: от 0 до 255
  3. "plain «char: тот же диапазон, что и signed char или unsigned char, , определенные реализацией
  4. signed short: от -32767 до 32767
  5. unsigned short: От 0 до 65535
  6. signed int: от -32767 до 32767
  7. unsigned int: от 0 до 65535
  8. signed long: от -2147483647 до 2147483647
  9. unsigned long: от 0 до 4294967295
  10. signed long long: -9223372036854775807 до 9223372036854775807
  11. unsigned long long: от 0 до 18446744073709551615

AC Реализация ++ (или C) может определять размер типа в байтах sizeof(type) до любого значения, пока

  1. выражение sizeof(type) * CHAR_BIT оценивается как количество бит, достаточно высокое, чтобы содержат требуемые диапазоны, а
  2. упорядочение типа по-прежнему действует (например, sizeof(int) <= sizeof(long)).

Фактические диапазоны, специфичные для реализации, можно найти в заголовке <limits.h> в C или <climits> в C ++ (или даже лучше, templated std::numeric_limits в <limits>.

Например, вы найдете максимальный диапазон для int:

C:

#include <limits.h>
const int min_int = INT_MIN;
const int max_int = INT_MAX;

C ++:

#include <limits>
const int min_int = std::numeric_limits<int>::min();
const int max_int = std::numeric_limits<int>::max();
636
ответ дан Community 26 August 2018 в 21:43
поделиться

Для чисел с плавающей запятой существует стандарт (IEEE754) : поплавки - 32 бит, а удваивается 64. Это аппаратный стандарт, а не стандарт C ++, поэтому компиляторы теоретически могут определить float и double на какой-то другой размер, но на практике я никогда не видел архитектуры, которая использовала что-то другое.

8
ответ дан Crashworks 26 August 2018 в 21:43
поделиться

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

sizeof(short int) <= sizeof(int) <= sizeof(long int)

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

#ifdef SYSTEM_X
  #define WORD int
#else
  #define WORD long int
#endif

Затем вы можете использовать WORD, чтобы определить ваши переменные. Не то, чтобы мне это нравилось, но это самый портативный способ.

12
ответ дан Emiliano 26 August 2018 в 21:43
поделиться
all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all
7
ответ дан Hanky Panky 26 August 2018 в 21:43
поделиться

От Alex B В стандарте C ++ не указывается размер интегральных типов в байтах, но он указывает минимальные диапазоны, которые они должны удержать. Вы можете вывести минимальный размер в битах из требуемого диапазона. Вы можете вывести минимальный размер в байтах из этого и значение макроса CHAR_BIT, определяющего количество бит в байте (во всех, кроме самых неясных платформ, это 8, и оно не может быть меньше 8).

Еще одно ограничение для char состоит в том, что его размер всегда 1 байт или бит CHAR_BIT (отсюда и название).

Минимальные диапазоны, требуемые стандартом (стр. 22):

и диапазоны типов данных в MSDN:

подписанный символ: от -127 до 127 (обратите внимание, не от -128 до 127, это соответствует платформам с добавлением 1). unsigned char: от 0 до 255 «простой» символ : От -127 до 127 или от 0 до 255 (зависит от знака по умолчанию): короткое: -32767 до 32767 без знака short: от 0 до 65535, подписанное int: -32767 до 32767 unsigned int: от 0 до 65535, подписанное длиной: -2147483647 до 2147483647 без знака длинный: от 0 до 4294967295 подписан длинный длинный: -9223372036854775807 до 9223372036854775807 unsigned long long: от 0 до 18446744073709551615 Реализация C ++ (или C) может определять размер типа в байтах sizeof (type) для любого значения, до тех пор, пока

выражение sizeof (type) * CHAR_BIT оценивает количество бит, достаточное для того, чтобы содержать требуемые диапазоны, и упорядочение типа остается в силе (например, sizeof (int) & lt; = sizeof (long)). Фактические диапазоны конкретных реализаций можно найти в заголовке на C или в C ++ (или даже лучше, в шаблоне std :: numeric_limits в заголовке).

Например, таким образом вы найдете максимальный диапазон для int:

C:

#include <limits.h>
const int min_int = INT_MIN;
const int max_int = INT_MAX;

C ++:

#include <limits>
const int min_int = std::numeric_limits<int>::min();
const int max_int = std::numeric_limits<int>::max();

Это правильно, однако вы также были правы в том, что: char: 1 byte short: 2 байта int: 4 байта: 4 байта float: 4 байта double: 8 байт

Поскольку 32-битные архитектуры по-прежнему по умолчанию и наиболее часто используются, и они сохранили эти стандартные размеры, поскольку pre -32-битные дни, когда память была менее доступной, а для обратной совместимости и стандартизации она осталась прежней. Даже 64-битные системы имеют тенденцию использовать их и имеют расширения / модификации. Пожалуйста, обратитесь к этому для получения дополнительной информации:

http://en.cppreference.com/w/cpp/language/types

0
ответ дан JCoder 26 August 2018 в 21:43
поделиться

На практике такой вещи нет. Часто вы можете ожидать, что std::size_t будет представлять собственный целочисленный размер без знака в текущей архитектуре. т.е. 16-разрядный, 32-разрядный или 64-разрядный, но это не всегда так, как указано в комментариях к этому ответу.

Что касается всех других встроенных типов, действительно зависит от компилятора. Вот два отрывка из текущего рабочего проекта последнего стандарта C ++:

Существует пять стандартных стандартных целочисленных типов: подписанный char, short int, int, long int и long long int. В этом списке каждый тип содержит как минимум столько же памяти, сколько и предшествующие ему в списке.

Для каждого стандартного целочисленного типа со знаком существует соответствующий (но другой) стандартный беззнаковый целочисленный тип: unsigned char, unsigned short int, unsigned int, unsigned long int и unsigned long long int, каждый из которых занимает один и тот же объем памяти и имеет те же требования к выравниванию.

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

81
ответ дан John Leidegren 26 August 2018 в 21:43
поделиться

Для 32-битных систем стандартом de facto является ILP32, то есть int, long и указатель - все 32-битные величины.

Для 64-битных систем, основным стандартом Unix de facto является LP64 - long, а указатель - 64-битный (но int - 32-разрядный). 64-битный стандарт Windows - LLP64 - long long, а указатель - 64-разрядный (но long и int оба 32-разрядные).

В свое время некоторые Unix-системы использовали ILP64.

Ни один из этих фактических стандартов не законодательно закреплен стандартом C (ISO / IEC 9899: 1999), но все они разрешены им.

И, по определению, sizeof(char) - 1, несмотря на тест в скрипте настройки Perl.

Обратите внимание, что были машины (Crays), где CHAR_BIT было намного больше 8. Это означало, что IIRC, что sizeof(int) также было 1, поскольку оба char и int были 32-битными.

210
ответ дан Jonathan Leffler 26 August 2018 в 21:43
поделиться

Нам разрешено определять синоним типа, чтобы мы могли создать собственный «стандарт».

На машине, в которой sizeof (int) == 4, мы можем определить:

typedef int int32;

int32 i;
int32 j;
...

Итак, когда мы передаем код на другую машину, на самом деле размер которой длинен int is 4, мы можем просто переопределить единственное вхождение int.

typedef long int int32;

int32 i;
int32 j;
...
9
ответ дан milan-j 26 August 2018 в 21:43
поделиться

Стандарт.

Стандарт C90 требует, чтобы стандарт

sizeof(short) <= sizeof(int) <= sizeof(long)

C99 требовал, чтобы

sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)

Вот спецификации C99 . Page 22 детализируют размеры разных интегральных типов.

Вот размеры (бит) типа int для платформ Windows:

Type           C99 Minimum     Windows 32bit
char           8               8
short          16              16
int            16              32
long           32              32
long long      64              64

Если вы заинтересованы в переносимости или хотите, чтобы имя типа отображало размер, вы можно просмотреть заголовок <inttypes.h>, где доступны следующие макросы:

int8_t
int16_t
int32_t
int64_t

int8_t гарантированно будет 8 бит, а int16_t гарантированно будет 16 бит и т. д.

79
ответ дан Mooing Duck 26 August 2018 в 21:43
поделиться

Существует четыре типа целых чисел, основанных на размере:

  • short integer: 2 byte
  • long integer: 4 байт
  • long long integer : 8 байт
  • integer: зависит от компилятора (16 бит, 32 бит или 64 бит)
38
ответ дан Peter Mortensen 26 August 2018 в 21:43
поделиться

Как уже упоминалось, размер должен отражать текущую архитектуру. Вы можете взять пик в limits.h, если хотите посмотреть, как ваш текущий компилятор обрабатывает вещи.

4
ответ дан Rohit Vipin Mathews 26 August 2018 в 21:43
поделиться
0
ответ дан Sirko 26 August 2018 в 21:43
поделиться
7
ответ дан user 26 August 2018 в 21:43
поделиться

Если вас интересует чистое решение на C ++, я использовал шаблоны и только стандартный код C ++ для определения типов во время компиляции на основе их размера бит. Это делает решение переносимым через компиляторы.

Идея очень проста: создайте список, содержащий типы char, int, short, long, long long (подписанные и неподписанные версии) и сканирование списка и по использование шаблона numeric_limits выбирает тип с заданным размером.

Включая этот заголовок, вы получаете 8 типов stdtype :: int8, stdtype :: int16, stdtype :: int32, stdtype :: int64, stdtype :: uint8 , stdtype :: uint16, stdtype :: uint32, stdtype :: uint64.

Если какой-либо тип не может быть представлен, он будет оцениваться как stdtype :: null_type, также объявленный в этом заголовке.

КОДЕКС НИЖЕ НЕ ПРЕДОСТАВЛЯЕТСЯ БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ПОЖАЛУЙСТА, ДВОЙНАЯ ПРОВЕРКА. Я НОВЫЙ В МЕТАПРОГРАММИРОВАНИИ СЛИШКОМ, ЧУВСТВУЮТ, ЧТОБЫ ИЗМЕНИТЬ И ИСПРАВИТЬ ЭТОТ КОД. Протестировано с DevC ++ (поэтому версия gcc около 3.5)

#include <limits>

namespace stdtype
{
    using namespace std;


    /*
     * THIS IS THE CLASS USED TO SEMANTICALLY SPECIFY A NULL TYPE.
     * YOU CAN USE WHATEVER YOU WANT AND EVEN DRIVE A COMPILE ERROR IF IT IS 
     * DECLARED/USED.
     *
     * PLEASE NOTE that C++ std define sizeof of an empty class to be 1.
     */
    class null_type{};

    /*
     *  Template for creating lists of types
     *
     *  T is type to hold
     *  S is the next type_list<T,S> type
     *
     *  Example:
     *   Creating a list with type int and char: 
     *      typedef type_list<int, type_list<char> > test;
     *      test::value         //int
     *      test::next::value   //char
     */
    template <typename T, typename S> struct type_list
    {
        typedef T value;
        typedef S next;         

    };




    /*
     * Declaration of template struct for selecting a type from the list
     */
    template <typename list, int b, int ctl> struct select_type;


    /*
     * Find a type with specified "b" bit in list "list"
     *
     * 
     */
    template <typename list, int b> struct find_type
    {   
        private:
            //Handy name for the type at the head of the list
            typedef typename list::value cur_type;

            //Number of bits of the type at the head
            //CHANGE THIS (compile time) exp TO USE ANOTHER TYPE LEN COMPUTING
            enum {cur_type_bits = numeric_limits<cur_type>::digits};

        public:
            //Select the type at the head if b == cur_type_bits else
            //select_type call find_type with list::next
            typedef  typename select_type<list, b, cur_type_bits>::type type;
    };

    /*
     * This is the specialization for empty list, return the null_type
     * OVVERRIDE this struct to ADD CUSTOM BEHAVIOR for the TYPE NOT FOUND case
     * (ie search for type with 17 bits on common archs)
     */
    template <int b> struct find_type<null_type, b>
    {   
        typedef null_type type;

    };


    /*
     * Primary template for selecting the type at the head of the list if
     * it matches the requested bits (b == ctl)
     *
     * If b == ctl the partial specified templated is evaluated so here we have
     * b != ctl. We call find_type on the next element of the list
     */
    template <typename list, int b, int ctl> struct select_type
    {   
            typedef  typename find_type<typename list::next, b>::type type; 
    };

    /*
     * This partial specified templated is used to select top type of a list
     * it is called by find_type with the list of value (consumed at each call)
     * the bits requested (b) and the current type (top type) length in bits
     *
     * We specialice the b == ctl case
     */
    template <typename list, int b> struct select_type<list, b, b>
    {
            typedef typename list::value type;
    };


    /*
     * These are the types list, to avoid possible ambiguity (some weird archs)
     * we kept signed and unsigned separated
     */

    #define UNSIGNED_TYPES type_list<unsigned char,         \
        type_list<unsigned short,                           \
        type_list<unsigned int,                             \
        type_list<unsigned long,                            \
        type_list<unsigned long long, null_type> > > > >

    #define SIGNED_TYPES type_list<signed char,         \
        type_list<signed short,                         \
        type_list<signed int,                           \
        type_list<signed long,                          \
        type_list<signed long long, null_type> > > > >



    /*
     * These are acutally typedef used in programs.
     * 
     * Nomenclature is [u]intN where u if present means unsigned, N is the 
     * number of bits in the integer
     *
     * find_type is used simply by giving first a type_list then the number of 
     * bits to search for.
     *
     * NB. Each type in the type list must had specified the template 
     * numeric_limits as it is used to compute the type len in (binary) digit.
     */
    typedef find_type<UNSIGNED_TYPES, 8>::type  uint8;
    typedef find_type<UNSIGNED_TYPES, 16>::type uint16;
    typedef find_type<UNSIGNED_TYPES, 32>::type uint32;
    typedef find_type<UNSIGNED_TYPES, 64>::type uint64;

    typedef find_type<SIGNED_TYPES, 7>::type    int8;
    typedef find_type<SIGNED_TYPES, 15>::type   int16;
    typedef find_type<SIGNED_TYPES, 31>::type   int32;
    typedef find_type<SIGNED_TYPES, 63>::type   int64;

}
1
ответ дан user781847 26 August 2018 в 21:43
поделиться

Существует стандарт, и он указан в различных документах стандартов (ISO, ANSI и еще что-то).

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

Однако даже со стандартным компилятором C ++ вы можете легко найти следующий фрагмент кода:

#include <iostream>
#include <limits>


int main() {
    // Change the template parameter to the various different types.
    std::cout << std::numeric_limits<int>::max() << std::endl;
}

Документация для std :: numeric_limits можно найти в Roguewave . Он включает в себя множество других команд, которые вы можете вызвать, чтобы узнать различные пределы. Это можно использовать с любым произвольным типом, который передает размер, например std :: streamsize.

Ответ Джона содержит лучшее описание, которое гарантировано. Независимо от того, на какой платформе вы находитесь, есть еще одна хорошая страница, которая более подробно описывает, сколько бит каждый тип ДОЛЖЕН содержать: int types , которые определены в стандарте.

Надеюсь, это поможет!

7
ответ дан X-Istence 26 August 2018 в 21:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: