В своей библиотеке стараюсь писать кроссплатформенный код, где это возможно, по стандарту C++, так что для интегральных типов использую только стандартную «десятку» (signed char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long) и никаких виндовых DWORD, __int64 и т.п. Тем не менее, иногда хочется определить тип именно 4 байта, чтобы точно 4, а не «системное слово», «размер адреса» и т.п. Стандарт C++ по этому поводу лишь говорит нараспев: char не может быть больше short, который не может быть больше int, который не может быть больше long, который не может быть больше long long.

Приобщившись к магии обобщённого программирования с помощью шаблонов, решил реализовать кроссплатформенный класс, который генерирует интегральный тип нужного размера во время компиляции. Основные приёмы, который я для этого использую — это рекурентное переопределение типов и частичная специализация шаблонов.

Начнём с формализации определения. Для каждого стандартного типа нужно определить «следующий» тип, необходимый для алгоритма перебора подходящих вариантов. С помощью частичной специализации реализуем шаблон type_traits:

    template<typename type> struct type_traits;
    template<> struct type_traits <unsigned char> { typedef unsigned char current_type; typedef unsigned short next_type; };
    template<> struct type_traits <unsigned short> { typedef unsigned short current_type; typedef unsigned int next_type; };
    template<> struct type_traits <unsigned int> { typedef unsigned int current_type; typedef unsigned long next_type; };
    template<> struct type_traits <unsigned long> {	typedef unsigned long current_type; typedef unsigned long long next_type; };
    template<> struct type_traits <unsigned long long int> { typedef unsigned long long int current_type; };
    template<> struct type_traits <signed char> { typedef signed char current_type; typedef short next_type; };
    template<> struct type_traits <short> { typedef short current_type; typedef int next_type; };
    template<> struct type_traits <int> { typedef int current_type; typedef long next_type; };
    template<> struct type_traits <long> { typedef long current_type; typedef long long next_type; };
    template<> struct type_traits <long long int> { typedef long long int current_type;};

Особенность типов (unsigned) long long int в том, что next_type для них не определён, так как больше них гарантированно ничего нет.

Далее следует определить основной шаблон алгоритма выбора, который содержит два параметра: type — это стандартный числовой тип и bool'евую переменная, которая равна true, если данный тип подходит по размеру или false если не подходит. В реализации по умолчанию берём у type «текущий тип» — type_traits::current_type, а в случае если тип не подходит, берём «следующий» — type_traits::next_type:

// Алгоритм выбора типа
    template<typename type, bool> 
    struct type_choice 
    { 
        typedef typename type_traits<type>::current_type std_type; 
    };
    template<typename type> 
    struct type_choice<type, false> 
    { 
        typedef typename type_traits<type>::next_type next_type; 
        typedef typename type_choice<next_type, sizeof(next_type) == capacity>::std_type std_type; 
    };

Третий служебный шаблон предназначен для выбора начального варианта, которых у нас два, в зависимости от того, хотим ли мы использовать знаковый или беззнаковый тип — char или unsigned char:

    // Базовый тип для начала подбора
    template <bool is_signed> struct base_type_selector { typedef signed char base_type; };
    template <> struct base_type_selector<false> { typedef unsigned char base_type; };

Наконец, нужно определить главный класс, который и будет содержать нужный тип. Я назвал этот класс fixed_int, он имеет два шаблонных параметра: первый параметр имеет тип size_t и обозначает желаемую ёмкость в байтах, второй параметр булевый и отвечает за знак типа. Сам же класс из открытых сущностей содержит лишь один волшебный typedef:

typedef typename type_choice< typename base_type_selector<is_signed>::base_type, sizeof(base_type_selector<is_signed>::base_type) == capacity >::std_type type;

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

template <size_t capacity, bool is_signed>
class fixed_int
{	
    // Описание ошибки компиляции в случае использования не поддерживаемой размерности 
    template <int x> struct unsupported_capacity { int i[1/(x-x)]; };
    template <> struct unsupported_capacity<1> {};
    template <> struct unsupported_capacity<2> {};
    template <> struct unsupported_capacity<4> {};
    template <> struct unsupported_capacity<8> {};

    // Свойства базовых типов, необходимые для перебора
    template<typename type> struct type_traits;
    template<> struct type_traits <unsigned char> { typedef unsigned char current_type; typedef unsigned short next_type; };
    template<> struct type_traits <unsigned short> { typedef unsigned short current_type; typedef unsigned int next_type; };
    template<> struct type_traits <unsigned int> { typedef unsigned int current_type; typedef unsigned long next_type; };
    template<> struct type_traits <unsigned long> {	typedef unsigned long current_type; typedef unsigned long long next_type; };
    template<> struct type_traits <unsigned long long int> { typedef unsigned long long int current_type;  typedef unsupported_capacity<capacity> next_type; };
    template<> struct type_traits <signed char> { typedef signed char current_type; typedef short next_type; };
    template<> struct type_traits <short> { typedef short current_type; typedef int next_type; };
    template<> struct type_traits <int> { typedef int current_type; typedef long next_type; };
    template<> struct type_traits <long> { typedef long current_type; typedef long long next_type; };
    template<> struct type_traits <long long int> { typedef long long int current_type;  typedef unsupported_capacity<capacity> next_type;};

    // Алгоритм выбора типа
    template<typename type, bool> 
    struct type_choice 
    { 
        typedef typename type_traits<type>::current_type std_type; 
    };
    template<typename type> 
    struct type_choice<type, false> 
    { 
        typedef typename type_traits<type>::next_type next_type; 
        typedef typename type_choice<next_type, sizeof(next_type) == capacity>::std_type std_type; 
    };

    // Базовый тип для начала подбора
    template <bool is_signed> struct base_type_selector { typedef signed char base_type; };
    template <> struct base_type_selector<false> { typedef unsigned char base_type; };

public:

    typedef typename type_choice< typename base_type_selector<is_signed>::base_type, sizeof(base_type_selector<is_signed>::base_type) == capacity >::std_type type;

};

Менее умные компиляторы могут такой конструкции не понять, например Qt жалуется на частичную специализацию шаблонного класса внутри другого шаблонного класса. Для таких случаев служебные внутренние шаблоны можно вынести отдельно в namespace __private, чтобы не замусоривать общее пространство имён, такой способ в подобных случаях использует Александреску в своей библиотеке Loki (например, для списков типов).

Осталось добавить удобные имена для всех типов, например так:

typedef fixed_int<1, false>::type	uint8;
typedef fixed_int<2, false>::type	uint16;
typedef fixed_int<4, false>::type	uint32;
typedef fixed_int<8, false>::type	uint64;
typedef fixed_int<1, true>::type	int8;
typedef fixed_int<2, true>::type	int16;
typedef fixed_int<4, true>::type	int32;
typedef fixed_int<8, true>::type	int64;

… и проверить что-же из всего этого получилось (запущено под MVS2015/intel 0x86):

...
int32 x1;
uint64 x2;
fixed_int<2, true>::type x3;

std::wcout<<typeid(x1).name()<<std::endl;
std::wcout<<typeid(x2).name()<<std::endl;
std::wcout<<typeid(x3).name()<<std::endl;
...

Результат:

int
unsigned __int64
short

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

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

 // Описание ошибки компиляции в случае использования не поддерживаемой размерности 
    template <int x> struct unsupported_capacity { int i[1/(x-x)]; };
    template <> struct unsupported_capacity<1> {};
    template <> struct unsupported_capacity<2> {};
    template <> struct unsupported_capacity<4> {};
    template <> struct unsupported_capacity<8> {};

Небесспорный главным образом потому, что описание ошибок в стандарте не определены, и потом польза такого класса не гарантированна. Компилятора Microsoft при попытке инстанцировать вот такой тип fixed_int<3, true>::type выдаёт ошибку:

exp4.cpp(127): error C2057: expected constant expression
exp4.cpp(156) : see reference to class template instantiation 'fixed_int<3,true>::unsupported_capacity<3>' being compiled
...


P.S.: Заменил типы char на signed char и (unsigned) long long на (unsigned) long long int

Комментарии (73)


  1. torkve
    30.03.2016 15:43
    +32

    #include <stdint.h>
    
    uint32_t x = 42;


    1. torkve
      30.03.2016 15:44
      +18

      На всякий случай: это есть в стандарте


      1. khim
        30.03.2016 17:32
        +1

        Ну тут как бы сама преамбула немного намекает на тему, что это типичный случай когда "рад бы в рай, да грехи не пускают". Windows — сильно особая платформа. Там больше 10 лет ушло на то, чтобы этот простейший заголовочный файл создать. Но да, не то в 2010й, не то в 2012й версии он наконец-то появился. Уря! Костыли можно потихоньку выкидывать...


        1. torkve
          30.03.2016 17:43

          <сарказм>А что же делать с VC 6, она же наверное эти вообще шаблоны не скомпилирует</сарказм>


          1. khim
            30.03.2016 17:49

            <прикинувшись ветошью>Почему это не скомпилирует? Скомпилирует, скорее всего. Сейчас под рукой VC 6 нету, но я не вижу тут ничего, что могло бы помешать этому на VC 6 собраться. Там проблемы с частичной специализацией были, но тут её вроде как нету...</прикинувшись ветошью>
            На самом деле я сталкивался с проектами, собиравшимися VC 6 ещё не так давно. Вы думаете статьи подобные этой на ровном месте возникают?


            1. torkve
              30.03.2016 19:17

              Я думаю и даже знаю, что до сих пор есть современные проекты, которые пишут на ASP (не ASP.Net) и PHP4. Но надо ж как-то из анабиоза выходить.


          1. burov_dmitri
            30.03.2016 19:39
            +1

            Может и не скомпилить. Qt компилит, только если вынести внутренние шаблоны из класса. Сам класс я написал в 2011-м году и честно говоря тогда даже не знал о stdint.h


            1. Antervis
              31.03.2016 10:27
              -1

              по факту, stdint.h появился в том же самом 11-м стандарте, в котором появились type_traits (всякие std::is_signed и подобное), которые ты использовал в своем хедере


              1. Ogra
                31.03.2016 11:15
                +2

                stdint.h появился в стандарте С99. Это cstdint появился в 11-м стандарте =)


        1. FoxCanFly
          30.03.2016 19:00
          +1

          #ifdef _MSC_VER && _MSC_VER <= BAD_MSC_VER
          typedef __int64 int64_t
          //....
          #else
          #include <cstdint>
          #endif

          ?


        1. Gorthauer87
          30.03.2016 19:04

          А разве в сети не найти файл stdint.h? когда у иная возникла проблема его отсутствия, я его выбрал из mingw и всё.
          Хотя в качестве концепта такая магия может и интересна где нибудь на bare metal железе. Но даже для них можно взять newlib.


          1. MacIn
            30.03.2016 19:19

            Это инженерный подход, так не интересно! sarcasm mode off


        1. Gorthauer87
          30.03.2016 19:04

          А разве в сети не найти файл stdint.h? когда у иная возникла проблема его отсутствия, я его выбрал из mingw и всё.
          Хотя в качестве концепта такая магия может и интересна где нибудь на bare metal железе. Но даже для них можно взять newlib.


  1. kosmos89
    30.03.2016 15:44
    +7

    А чем cstdint не угодил?


    1. burov_dmitri
      30.03.2016 16:23
      -4

      Да почему же, он всем хорош. Наверное это и вправду велосипед, но я привык уже его использовать


      1. khim
        30.03.2016 17:33
        +5

        Хотите — используйте. Но хотя бы замените в нём char на signed char, если хотите переносимости!


        1. burov_dmitri
          30.03.2016 19:36

          Вы правы, если уж я сослался на ISO, то нужно и long long заменить на long long int, хотя честно я не работал в системах где нет таких синонимов.


          1. mayorovp
            30.03.2016 20:11
            +3

            Дело не в синонимах. Дело в том, что тип данных char может быть как знаковым, так и нет, в зависимости от настроек компилятора.


            1. khim
              30.03.2016 20:16

              Именно. А "long long" — это как раз стандарт. "Неявный int" можно опускать...


              1. burov_dmitri
                31.03.2016 01:35

                … и я тоже так считал, однако в 3.9.1. пунктах 2 и 3 указан именно long long int (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf).


                1. khim
                  31.03.2016 02:58

                  При чём тут 3.9.1? Там типы перечислены. Как их можно в программе называть — в 7.1.6.2 написано.


  1. Hokum
    30.03.2016 15:48
    +1

    Интересное решение. А чем Вас не устраивают целочисленные типы из стандарта C++11?


    1. burov_dmitri
      30.03.2016 19:47
      -1

      Типы из cstdint меня устраивают полностью, я написал класс вычисляемого размера в 2011-м и тогда даже не знал о cstdint.


  1. StrangerInRed
    30.03.2016 15:52
    -23

    «Вот тебе шаблоны — начинай велосипедить»
    oh my fucking god.
    Шаблонная магия С++ разрабов, как они есть.
    P.S. Вот он уровень инвайтов на хабре.


    1. rotor
      30.03.2016 18:45
      +4

      Вам не надоело тролить в каждом посте по C++? Или этоту вас весеннее?


      1. StrangerInRed
        30.03.2016 19:55
        -12

        Собираю лулзов с бугуртящих С++-девов.
        Жаль что stdint.h запретили. Или как там у вас, cstdint.h
        А чо тролить? Это ж откровенный велосипед, велосипеднее уже некуда карл.
        Чуваку надо было написать свой язык со своими типами.


        1. victor_k
          31.03.2016 13:59

          тебе должно понравиться: https://habrahabr.ru/post/279745/


  1. RPG18
    30.03.2016 16:39
    +1

    На самом деле, кто хотел на VS иметь stdint.h, тот имел благодаря проекту msinttypes.


    1. VioletGiraffe
      30.03.2016 16:43

      Вообще-то в VS и так есть этот хедер, сколько себя помню. С VS2012 точно.


      1. comargo
        30.03.2016 20:59

        stdint.h появился в VisualStudio начиная с десятой версии (которая VS 2010). В девятой версии (VS2008) ее нет.


  1. khim
    30.03.2016 17:29
    +2

    А насчёт "десятки стандартных типов" — это такая шутка? Вообще-то стандартных типов не 10, а 11. Про "signed char" вы забыли. Тот факт что по-умолчанию char может быть не только теоретически, но и практически любым выпило много крови тем, кто переносит код с x86 (где на большинстве компиляторов он знаковый) на ARM (где по умолчанию он беззнаковый).


    1. burov_dmitri
      30.03.2016 21:04

      Я уже отписался выше, это не шутка, это ошибка. Конечно signed char как и long long int. Конечно о 10-ке (как и о 11-и) говорить не корректно, лучше просто сослаться на параграф 3.9.1., пункты 2 и 3 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf


  1. khim
    30.03.2016 17:43

    Только сейчас прочитав статью заметил "небесспорный приём". Во-первый — он таки "бесспорный" (см. SFINAE). Во-вторых — ненужный.
    В большинстве случаев будет достаточным сделать так:

    template <int x> struct unsupported_capacity;
    template <> struct unsupported_capacity<1> {};
    template <> struct unsupported_capacity<2> {};
    template <> struct unsupported_capacity<4> {};
    template <> struct unsupported_capacity<8> {};

    Это, правда, даст возможность описывать указатели на, скажем, "struct unsupported_capacity<3>" — но практически этого достаточно: где-то же в программе вы этот указатель захотите-таки разименовать? Вот там и получите ошибку...


    1. Mingun
      30.03.2016 18:34

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

      int i[8-x];


    1. burov_dmitri
      30.03.2016 21:06

      Спорность в том, что результат не гарантирован, а подыгран. Я не нашёл, чтобы стандарт предписывал в какой форме IDE должен сообщать об ошибках инстанцирования


  1. izvolov
    30.03.2016 19:43
    +12

    Интегральными бывают суммы, схемы и теоремы Коши. А типы — целочисленные.


    1. fareloz
      31.03.2016 12:42
      -4

      Вы мне напомнили моего преподавателя по алгебре в универе. Он говорил «числа бывают комплекснЫми. кОмплексные только обеды» )))


      1. mayorovp
        31.03.2016 13:37
        +3

        Первый раз вижу такое произношение, с ударением на "Ы" :) Обычно холивар идет между "О" и "Е"...


        1. fareloz
          31.03.2016 17:49

          да, так и есть, я ошибся, быстро писал


  1. lorc
    30.03.2016 19:47
    +3

    Хочу немного позанудствовать. Вам никто не обещал что char будет иметь размер в один октет. Иными словами, тот факт что sizeof(char) == 1 не значит что char занимает ровно 8 бит. Он может быть размером 32 бита.
    Вряд ли ваш код попадет на платформу где такое имеет бысто быть. Но если вдруг попадет — он там попросту сломается.
    Поэтому, он не совсем кроссплатформенный.
    Стандарт, кстати, гарантирует только сущесвование типов а-ля int_leastХХ_t и говорит что могут существовать системы где intXX_t просто не определен.


    1. StrangerInRed
      30.03.2016 20:00
      -1

      POSIX обещал. Там где есть поддержка POSIX sizeof(char) == 1


      1. MikalaiR
        30.03.2016 21:00
        +1

        1 байт != 8 бит, как ни странно. 1 байт — минимальная адресуемая единица памяти.


        1. StrangerInRed
          30.03.2016 21:15

          Парень не оперирует словом байт. Он оперирует словом ОКТЕТ. Будьте добры загуглите и поймите что октет это всегда строго 8 бит.


          1. MikalaiR
            30.03.2016 21:22
            +1

            "Парень" прав. 1 байт не всегда == 1 октет. На x86 они равны, но есть архитектуры, где 1 байт = 4 октета.


            1. StrangerInRed
              30.03.2016 21:28
              +1

              >sizeof(char) == 1
              имеется ввиду именно один октет, в стандарте так и написано

              An individually addressable unit of data storage that is exactly an octet, used to store a character or a portion of a character; see also Character. A byte is composed of a contiguous sequence of 8 bits. The least significant bit is called the «low-order» bit; the most significant is called the «high-order» bit.


              1. MikalaiR
                30.03.2016 21:35
                +1

                Тогда извиняюсь, был неправ. Но оператор sizeof всё-таки возвращает размер в байтах, а не в октетах.


                1. khim
                  30.03.2016 21:49
                  +2

                  По моему вы спорите "мимо" друг друга. Есть стандарт ANSI/ISO C (на самом деле теоретически это разные стандарты). Есть стандарт POSIX (который, кстати, Windows и не поддерживает сегодня — но поддерживала много лет назад).
                  В ANSI/ISO C размер байта не фиксирован. Может быть 8 бит, может быть 9, а может и все 36. Как карта ляжет. В POSIX — размер байта фиксирован. 8 бит без вариантов. Хотите ли вы поддерживать не-POSIX — системы (+Windows: из-за "наследственности там много чего реализовано "как в POSIX"), или весь спектр ANSI/ISO C систем? Это уж вам решать...


                  1. StrangerInRed
                    31.03.2016 08:33
                    -4

                    Я говорил конкретно про POSIX. И не надо тут разводить про поддержку не-POSIX. Была четкая конкретика.


                    1. khim
                      31.03.2016 11:24
                      +3

                      Не очень понятно с какого перепугу вы завели разговор про POSIX при том что он, в общем-то, начался с не-POSIX-совместимой платформы!


      1. lorc
        31.03.2016 13:45

        sizeof(char)==1 везде, на любой системе где есть компилятор C или C++.
        Другое дело, что только POSIX гарантирует что длина байта равно 8 бит. ANSI C этого не обещает.


  1. izvolov
    30.03.2016 20:15
    -1

    Гениально. Автор, ты изобрёл линейный поиск.

    using integral_types = type_list<...>;
    using uint8_t = find_if_t<integral_types, is_unsigned && has_8_bits>;
    ...
    // Образно выражаясь.


  1. Eric50
    30.03.2016 21:07
    +1

    Потерян ещё один тип: «signed char».
    Действительно «signed int» идентичен типу «int».
    А вот: «unsigned char», «signed char» и «char», это три разных типа.


  1. menzoda
    30.03.2016 21:07
    +2

    Ну и кроме того не «интегральные», а «целочисленные». Интегральный это от слова integral, и связано это понятие с такой математической закорючкой. А целочисленный — это integer.


    1. develop7
      30.03.2016 21:11
      -1

      Prelude> :i Integral 
      class (Real a, Enum a) => Integral a where
        quot :: a -> a -> a
        rem :: a -> a -> a
        div :: a -> a -> a
        mod :: a -> a -> a
        quotRem :: a -> a -> (a, a)
        divMod :: a -> a -> (a, a)
        toInteger :: a -> Integer
          -- Defined in ‘GHC.Real’
      instance Integral Word -- Defined in ‘GHC.Real’
      instance Integral Integer -- Defined in ‘GHC.Real’
      instance Integral Int -- Defined in ‘GHC.Real’


    1. Eric50
      30.03.2016 21:23
      -7

      Логично называть целые числа со знаком "integer". И даже приемлимо всякое "int32" или "i32".
      А вот например названия "uint32" или даже "u32", уже нелогичны. Особенно если незнать о происхождении.
      Зато подходит иное название "натуральное число". Как вам: "natural32", "natural64"?
      Я для своих домашних проектиков давно создал хидер с псевдонимами:
      typedef signed int32 integer32;
      typedef unsigned
      int32 natural32;
      Мне так больше нравится. Более логичные названия.


      1. khim
        30.03.2016 21:57
        +6

        Срочно читать Фейнмана. Про "улучшенную тригонометрию". uint32_t может выглядеть безумием — но это стандарт. Любой, кто использует C/C++ должен про него знать. Хотя на практике, конечно, есть люди знающие C/C++ на уровне Эллочки-людоедки, но им ваши обозначения тоже не помогут.
        В программировании и без вас достаточно сложностей и непонятностей — незачем изобретать новые. С одной стороны ваши "домашние проектики" — они лично ваши и вы можете делать что хотите. С другой — а вдруг по работе пригодится? Всё переписывать только из-за того, что вам uint32_t не нравится?


      1. MacIn
        30.03.2016 21:59
        +1

        Более логичные с точки зрения кого? Signed/unsigned — стандарт. В процессоре (если говорить о x86) отдельно разведены команды signed и unsigned арифметики.


      1. JIghtuse
        30.03.2016 23:01

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

        Натуральные числа — это ряд чисел 1, 2, 3, …, представляющих собой число предметов или более строго — мощности (количества элементов) непустых конечных множеств.
        Первая ссылка в гугле

        unsigned же может иметь нулевое значение, ломая всю "абстракцию".


        1. Avitella
          30.03.2016 23:43

          В зарубежной литературе натуральные числа обычно начинаются с 0


      1. rotor
        30.03.2016 23:08

        Кстати, в натуральном ряде нет нуля, если уж вы о чистоте наименований.
        Таким образом ваш тип — это целые неотрицательные числа.
        Поэтому стандартное обозначение лучше отражает истиное положение вещей чем ваше.


        1. Eric50
          30.03.2016 23:14
          -1

          Спорно, является ли ноль натуральным числом. Некоторые допускают.
          Но я вас понял. Всем спасибо за вразумление. Исправлюсь!


          1. rotor
            30.03.2016 23:52

            Тут не очем спорить. Это математическое понятие, которое строго определено и не допускает никаких неоднозначностей.


            1. khim
              31.03.2016 03:05
              +1

              Если бы всё было так однозначно то не было бы всех этих ?0, ?0, ?*, ?+, ?1, ?>0...


              1. rotor
                31.03.2016 09:26
                -1

                Да, похоже, я был не прав. У меня математическое образование и мы всегда оперировали примерно таким

                определением
                image отсюда:


    1. mayorovp
      30.03.2016 23:44
      +3

      В английском языке, когда речь идет о типах данных, "integral" — это прилагательное, а "integer" — это существительное.
      "integral" переводится как "целочисленный", а "integer" — как "целое число".
      Значение "математическая закорючка" у слова "integral" тоже есть, но в этом значении это слово является уже существительным, а не прилагательным, поэтому никто не путается (кроме программистов по всему миру).


      1. MacIn
        31.03.2016 00:37
        +1

        Так то в английском. Здесь же проблема неверного перевода. Как, например, с "органической едой". Или "софистицировать". Или "экспертиза". Толпы их.


        1. mayorovp
          31.03.2016 09:50
          +1

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

          А целочисленный — это integer.


  1. McAaron
    31.03.2016 11:55
    +2

    Даже на одной аппаратной платформе, например x86_64 (ia32e), разные ОС по разному интерпретируют резиновые целочисленные типы, введенные в С/C++ в качестве базовых. Резиновые они потому, что стандарт не определяет их длины, он только вводит отношения
    sizeof(short int) \le sizeof(int) \le sizeof(long int) \le sizeof(long long int)
    Это значит, что не исключается случай, когда все эти типы будут иметь одинаковую длину.
    Разумеется, использовать эти типы можно лишь в том случае, если программа ничего не выводит и не выводит, потому что даже одна и та же программа, скомпилированная на разных платформах и/или разными компиляторами не сможет ввести данных, которые она вывела. Чтобы преодолеть это были введены жесткие типы, которые определены в stdint.h (). Эти типы локально настраиваются на соответсвующие резиновые в каждом конкретном случае установки компилятора на конкретную платформу, если таковые там присутствуют.
    Как только возникает необходимость в бинарном выводе/вводе, эти типы должны использоваться безусловно. Они обладают абсолютной переносимостью, поскольку описываются в обязательной части стандарта.
    Кстати, аналогичная ситуация может случиться при выводе/вводе символов — байт, вопреки расхожему мнению, это не 8 бит, а минимальная порция данных в адресуемой оперативной памяти. Так что запросто может случиться, что char может занимать, например, 12 бит.
    В этой связи гораздо более полезно читать стандарт, чем толстые книги, переиздаваемые чуть ли не каждый год. Кстати, стандарт нужно читать не весь, а только до приложений, поскольку в приложения попадают ангажированные тексты спонсоров, пытающиеся возглавить то, что не удается разрушить.


  1. burov_dmitri
    31.03.2016 11:58

    С этим не поспоришь, стандарт приоритетнее


  1. roman_kashitsyn
    31.03.2016 14:49
    +2

    Если не дают использовать новый стандарт, всегда можно взять <boost/cstdint.hpp>.


    1. izvolov
      31.03.2016 15:31
      +2

      Полностью поддерживаю. Только пожалуйста, не надо называть 11-й стандарт новым. Уже полтора более новых стандарта вышло.


      1. khim
        31.03.2016 16:07

        У всех разное понятие о "новизне". Многие и Fortran 90 "новым" называют, хотя с тех пор аж три с половиной новых стандарта вышло...


  1. vladon
    01.04.2016 17:02

    Вы большой молодец и у вас много времени. Но зачем это нужно было-то? На дворе 2016 год.