Search

2.4a — Fixed-width integers and the unsigned controversy

In the previous lesson 2.4 -- Integers you learned that C++ only guarantees that integer variables will have a minimum size -- but they could be larger, depending on the target system.

Why isn’t the size of the integer variables fixed?

The short, non-technical answer is that this goes back to C, when performance was of utmost concern. C opted to intentionally leave the size of an integer open so that the compiler implementers could pick a size for int that performs best on the target computer architecture.

Doesn’t this suck?

Yes! As a programmer, it’s a little ridiculous to have to deal with variables whose size could vary depending on the target architecture.

Fixed-width integers

To help with cross-platform portability, C99 defined a set of fixed-width integers (in the stdint.h header) that are guaranteed to have the same size on any architecture.

These are defined as follows:

Name Type Range
int8_t 1 byte signed -128 to 127
uint8_t 1 byte unsigned 0 to 255
int16_t 2 byte signed -32,768 to 32,767
uint16_t 2 byte unsigned 0 to 65,535
int32_t 4 byte signed -2,147,483,648 to 2,147,483,647
uint32_t 4 byte unsigned 0 to 4,294,967,295
int64_t 8 byte signed -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
uint64_t 8 byte unsigned 0 to 18,446,744,073,709,551,615

C++ officially adopted these fixed-width integers as part of C++11. They can be accessed by including the cstdint header, where they are defined inside the std namespace. Here’s an example:

Even though these weren’t adopted in C++ until C++11, because they were part of the C99 standard, some older C++ compilers offer access to these types, typically by including stdint.h. Visual Studio 2005 and 2008 do not include stdint.h, but 2010 does.

If you are using the boost library, boost provides these as part of <boost/cstdint.hpp>.

If your compiler does not include cstdint or stdint.h, the good news is that you can download Paul Hsieh’s pstdint.h cross-platform compatible version of the stdint.h header. Simply include the pstdint.h file in your project and it will define the fixed width integer types with the proper sizes for your platform.

Warning: int8_t and uint8_t may or may not behave like chars

Due to an oversight in the C++ specification, most compilers define and treat int8_t and uint8_t identically to types signed char and unsigned char respectively, but this is not required. Consequently, std::cin and std::cout may work differently than you’re expecting. We cover char types in more detail in section 2.7 -- Chars.

Until this is clarified by a future draft of C++, you should assume that int8_t and uint8_t may or may not behave like char types.

Integer best practices

Now that fixed-width integers have been added to C++, the best practice for integers in C++ is as follows:

  • int can be used when the integer size doesn’t matter and isn’t going to be large.
  • Fixed-width integers should be used in all other cases, especially when you need an integer with a guaranteed width.
  • Only use unsigned types if you have a compelling reason.

Some compilers define their own version of fixed width integers -- for example, Visual Studio defines __int8, __int16, etc… You should avoid these like the plague.

The controversy over unsigned numbers

Many developers (and some large development houses, such as Google) believe that developers should generally avoid unsigned integers. This is largely because unexpected behavior can result when you mix signed and unsigned integers.

Consider the following snippet:

What happens in this case? -1 gets converted to some large number (probably 4294967295), and your program goes ballistic. But even worse, there’s no good way to guard against this condition from happening. C++ will freely convert between signed and unsigned numbers, but it won’t do any range checking to make sure you don’t overflow your type.

Many modern programming languages (such as Java and C#) either don’t include unsigned types, or limit their use. Bjarne Stroustrup, the designer of C++, said, “Using an unsigned instead of an int to gain one more bit to represent positive integers is almost never a good idea”.

This doesn’t mean you have to avoid unsigned types altogether -- but if you do use them, use them only where they really make sense, and take care not to mix signed and unsigned numbers.

Alex’s note: Most of this tutorial was written prior to these fixed-width integers being adopted into C++11, so we may use int in some examples where a fixed-width integer would be more appropriate.

2.5 -- Floating point numbers
Index
2.4 -- Integers

62 comments to 2.4a — Fixed-width integers and the unsigned controversy

  • What is the benefit of using fixed-width integers? Are computations faster?

    • dudeperfect

      I guess fixed-width integers are useful, because they do not vary in different platforms. That means, you guarantee, that overflow won’t happen.

      • Alex

        Fixed-width integers are useful because their sizes are guaranteed, which helps ensure your code is portable to other systems.

        Overflow can still happen if you put a number outside of the integer’s range into the integer.

        • Syed

          Hi Alex,
          I am using Visual Studio 2015 on Win 8.1.Variable type int16_t and int32_t work fine but getting funny results for int8_t. Here is my code;
                  
          int main()
          {
                  int8_t newx(12);
              std::cout << newx<< std::endl;
              int16_t i(5); // implicit assignment
              std::cout << i<<std::endl;
                  int32_t newx2(32);
              std::cout << newx2 << std::endl;
              
                  return 0;
          }

          My Out Put:

          Symbol (like machine language)
          5
          32

          • Alex

            Unfortunately, the C++ standard allows int8_t to be defined as a typedef to a char. This is what Visual Studio does -- consequently, in Visual Studio, std::cout treats printing int8_t the same as printing a char. The char with ASCII code 12 is the form feed character, which probably doesn’t have a printable symbol in your console.

            You can get around this by using a static cast to force std::cout to print newx as an integer:

            Personally, I wish the standards committee had insisted that int8_t be its own integer type to avoid this kind of mess.

  • Patrick

    Fixed-width integers aren't necessarily better. Even without them, the C++ standard types give the guarantee about the minimum size a type of integer is, so avoiding overflow has never been a problem in this respect.

    The fixed-width integers are only good for making sure integers aren't bigger than they need to be; this is notably good for particularly high performance code, or working on dives with little memory; but also good for when doing low level code involving bitwise operations (e.g. an integer exponentiation algorithm).

    Otherwise though, letting the compiler choose the best size for each type of integer is likely to be the more efficient procedure. Finally, unsigned/long are arguably more semantically descriptive than uint16_t/int32_t.

  • Charley

    I can see the use of fixed width integers in single chip micro-controllers where available memory is severely restricted.

  • Charley

    I have kind of an unusual error here using Code Blocks. (My Visual Studio is only 2008.)

    When executing the following code the variable oneB is returning a character. in this case ‘M’.

    Got any idea how I screwed it up?

  • karma

    Hey Alex, I dont know if its a typo or if I am missing something, but in the textpart :"Fixed-width integers
    To help with cross-platform portability, C99 defined a set of fixed-width integers (in the stdint.h header) that are guaranteed to have the same size on any architecture. These are defined as follows:"

    instead of C99 shouldnt it be C++? Or what is C99 referring to?

    Thanks, -Karma

    • Alex

      C99 is an update to the C language (upon which C++ is based) released in the year 1999. C99 introduced (amongst other things) the fixed-width integers to the C language. C++ adopted these fixed-width integers in C++11 (the updated to C++ made in the year 2011), however, before that point, many C++ compilers provided support for them anyway.

  • Peter Charters

    Concerning the controversy re unsigned integers here is one major benefit:
    Most of the "computers" on the planet are small single chip machines that (for the most part) operate in the real world on real time. Most of these microcontrollers require the computation of real time intervals. Fortunately, they have access to a 16- or 32-bit hardware or software timer/counter that is incremented by pulses derived from a quartz crystal or equivalent. Reading the counter, one gets an unsigned integer. Unfortunately, the timer/counter will roll over at some point and repeat its sequence of numbers. Unsigned integers to the rescue! If A is the latest reading and B is an earlier reading, A - B is the interval; using unsigned arithmetic, this works regardless of when the rollover occurs, as long as the A - B interval is shorter than the time for the timer/counter to roll over.

  • cpplx

    I cant figure out the "_t" part of this fixed width integers (int16_t). why it is named like that?

  • Odgarig

    Thanks for the great tutorial.So because of the integers size’s are different on different architectures, fixed width integers guarantees that any computer architectures will treat fixed with integers as same size and also benefits larger size ?

    • Alex

      Yes, the fixed width integers have a guaranteed size (whereas non-fixed-width integers only have a guaranteed minimum size, and could be larger).

      I’m not sure what you mean by “also benefits larger size”.

      • Odgarig

        I meant to say"fixed-width integers can hold larger value than non-fixed-width integers?".

        • Alex

          > I meant to say”fixed-width integers can hold larger value than non-fixed-width integers?”.

          No. A fixed-width integer and a non-fixed-width integer of the same size are identical.

  • IllidanS4

    C# does include unsigned integer types, but most of them aren’t CLS compliant.

  • Hi Alex,

    After reading the first couple of chapters of your tutorial, I have written a program to test whether the input is a prime number.

    These are a couple of declarations from my main.cpp which contains my main() function. I have not used "#include <stdint.h>" to define uint64_t, yet my program still works perfectly as far as I can tell and the visual studio code analysis does not pick up any problems either. Why is this?

    I’ll continue reading your tutorial, thanks for all of the hard work you have put in!

  • Giovanni

    I’m using code blocks and I’m having an odd error when trying to #include <cstdint>. When I try to run my code it gives me an error and brings up a header file called "c++0x_warning.h". Here is the code inside of it.

    [#ifndef _CXX0X_WARNING_H
    #define _CXX0X_WARNING_H 1

    #ifndef __GXX_EXPERIMENTAL_CXX0X__
    #error This file requires compiler and library support for the
    ISO C++ 2011 standard. This support is currently experimental, and must be
    enabled with the -std=c++11 or -std=gnu++11 compiler options.
    #endif

    #endif]

    When I try to use the cross platform version of the stdint.h header  that you suggested it keeps saying that there
    is no such file or directory as "pstdint.h"

    Could it maybe be that I haven’t enabled the <cstdint> file in code::blocks yet? Your advice would help a lot. Thanks.

    • Alex

      Code::Blocks supports it, you just have to turn it on. You should find support for C++11 in your project settings.

      Go to Toolbar -> Settings -> Compiler
      Select the “compiler settings” tab and then the “compiler flags” tab
      Check the box for “Have g++ follow the C++11 ISO C++ language standard [-std=c++11]”

    • Jim

      Giovonnie,

      Try this to fix your problem in code::blocks.
      go to Main menu settings-> compiler and click on the box about 10 boxes down on the list you’ll see there.  It reads something like this: Have g++ follow the C++ ISO….etc..
      Make sure the box is checked and restart code::blocks.
      Good Luck!

  • Banelus

    Which one would you suggest using: int8_t/uint8_t or char/usigned char? Because I encountered some errors when using fixed version and I want to know what’s your opinion.

    • Alex

      Personally, I’d use char/unsigned char for variables I wanted to hold characters, and int8_t for variables I wanted to hold integers.

      Many compilers typedef int8_t as signed char and uint8_t as unsigned char, but it’s not guaranteed they’ll be treated the same.

  • Jim

    Alex,
    Am I missing something between integers and fixed width integers here? I just can’t get the difference between the two through my thick head.  Both have signed and unsigned and both have the same range of integers. They both use the same amount of bytes.  

    Yet one uses short, long and long long and the other uses int16_t, int32_t and int64_t. Yes! (I left out char and int8_t).

    Can you explain the difference and give a few example of how they are used. Having to worry about and integers size is still a pain!

    • Alex

      The normal integers and fixed width integers are very similar. The only difference is that the normal integers may vary in size on different architectures (e.g. an int may be 2 bytes on one architecture and 4 bytes on another). The fixed width integers have a guaranteed size (e.g. int32_t is always 4 bytes). That’s the only difference.

      You’ll still need to worry about size to make sure you’re picking an integer with a big enough range for the things you want to do with it, but at least with the fixed width integer you know exactly how large each integer actually is.

      Use of the standard integers and fixed width integers is identical:

  • Phil

    Can int64_t and uint64_t be used on a 32 bit device/computer?

  • Jim

    Alex,

    You wrote:
    "If your compiler does not include cstdint or stdint.h, the good news is that you can download Paul Hsieh’s pstdint.h cross-platform compatible version of the stdint.h header."

    These may be a dumb questions. But isn’t one of these in the standard library? Isn’t the standard library information available in all compiler?

    What do you mean when you say the Integer has a minimum size?

  • Jim

    More questions:

    Without going into details. If you needed to download any header like pstdint.h.  Wouldn’t we have to go through a lot of steps to install and use it?  Is this something that a beginner could do?

    What is a boost library?

    Since fixed width integers have the same range of values as(signed and unsigned)short, int, long, and long long. Is there any reason to use the later at all. How do we code char (signed or unsigned) as integers?

    • Alex

      > If you needed to download any header like pstdint.h. Wouldn’t we have to go through a lot of steps to install and use it? Is this something that a beginner could do?

      Nope. You don’t need to install it. You just download the file, copy it into your C++ project folder, add it to your project like any other header file, and then #include it wherever you need it. Anybody should be able to do this after completing chapter 1 of this tutorial.

      > What is a boost library?

      Much like how the C++ standard library provides a lot of additional functionality beyond the core language, Boost is a 3rd party C++ library that also provides a lot of additional functionality. You won’t need it for these tutorials, but when you start getting into more advanced applications, using the Boost library can increase your efficiency by allowing you to use off-the-shelf and pre-tested code to do things rather than having to write your own.

      > Since fixed width integers have the same range of values as(signed and unsigned)short, int, long, and long long. Is there any reason to use the later at all.

      Yes, in one case. It’s acceptable to use type int when you need an integer where the size doesn’t really matter (e.g. as a loop variable), because using int may be more performant than using a fixed-width integer of a smaller size.

  • Newcomer11

    Hi Alex

    If I need to store an address such as 0x22334455, what would be the best type to store it as? (I sometimes see DWORD from window.h used for this purpose, but I’m not sure if this cornforms to best practices)

    Would this need be a compelling reason to use something like unsigned int?

    Or should I use a void pointer, from chapter 6?
    (As in: void *abc = static_cast^void*^ (0x22334455), I used ^ for angle brackets since for some reason my phone does not have angle brackets)

    Thank you

  • Amlan

    Hi Alex,

    In this code snippet taken from your lesson:

    unexpected result will occur and -1 will get converted to a large value. I want to know: what is the process followed by the compiler to convert this -1 to reach at a particular value?

    Thanks.

    • Alex

      According to the C++ spec, “If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2^n where n is the number of bits used to represent the unsigned type).”

      The bit pattern for -1 signed is the same as for 4,294,967,295 unsigned, so you pass in an argument of -1 and x gets the value of 4,294,967,295.

  • Toast Muncher

    Hi,
    first of all, thanks a lot for all the time and effort you’ve put into this great site!

    Since the whole point of using standard width variables is cross-platform portability, I was wondering if you would recommend using cstdint (which requires C++11 support), or stdint.h (you said, for example that Visual Studio 2005 and 2008 do not support this).

    Since C++11 is now 5 years old I would assume that generally it would be supported by C++ compilers, but in the IDE I use, CodeLite, it needs to always first be activated in the individual project settings for the compiler, so perhaps its not quite as widespread as I thought?

    Thanks in advance! 🙂

    • Alex

      Definitely use fixed width integers (via cstdint) if you have a need. If your compiler isn’t C++11 compatible, the pstdint.h library is a good alternative that will work on most platforms. Or get a compiler that is. 🙂

  • J3ANP3T3R

    hey guys great tutorial website but i feel like i kind of just got lost in here from the basic section of the tutorial. what are we talking about exactly and should i really take a closer look at this topic ? i’m from Visual Foxpro 9.0 where we kind of just use INT. what are these _t types and do we commonly use them moving on or just use int ?  i don’t think i will ever use unsigned types. im also at a lost with "fixed width". im really slow at this point any help is greatly appreciated 🙁

    • Alex

      “Fixed width” simply means the size of the variable is fixed (e.g. it is guaranteed). int16_t will always be 2 bytes, for example. Fixed width integers are definitely useful, and you should use them anywhere you need an integer with a guaranteed size.

      When the size of an integer doesn’t really matter, we normally just use int. But in other cases, using an integer with a guaranteed width can allow you to either save space (by not using a variable that’s too large on some systems because it could be smaller on other systems) or ensure you’ve picked an integer that’s going to be large enough on all architectures to hold the data you need to store.

      • J3ANP3T3R

        i see thanks. but what is wrong with int ? if INT is not a fixed width integer what are the consequences of using INT ? do i for example lose data when using INT ? why cant INT be a fixed width integer instead of creating the _t data types ?

        • Alex

          The important thing to take away here is that the size of an int is not fixed. It could be 4 bytes. It could be 2 bytes. Therefore, if you’re relying on it to hold 4 bytes, you might get overflow on architectures where it can only hold 2 bytes. If you’re only relying on it to hold 2 bytes, you may be wasting space on architectures where it’s 4 bytes.

          In many cases, where we just need to hold a single small value (e.g. between -32,768 and 32,767) we use int because it’s simple and it works, and if we waste 2 bytes, so what?

          However, in other cases, memory use does matter (e.g. when you need to store 10,000 integers) or we need to store a larger number and need an integer that’s guaranteed to be large enough to hold that number, fixed-width integers are a better choice.

          Int wasn’t made a fixed-width integer because it wasn’t defined that way originally. C++ tends to add new things rather than change existing things, usually with backwards compatibility in mind. Otherwise, older programs that are relying on certain behavior might break.

  • J3ANP3T3R

    i just made a comparison with what i have been using in foxpro for years and found that my ideal c++ int type is int32_t.

    C++
    int32_t    4 byte signed    -2,147,483,648 to 2,147,483,647

    Foxpro
    Integer    Numeric value with no decimals 4 bytes    -2147483647 to 2147483647

    Question : if for example i will only be needing a small range INT like int8_t and if the user types in integers exceeding the range of int8_t that will cause an overflow and will make my application unstable or unreliable as it could store data that is different from what the user intended to key in. do i now have to create a way for my application to NOT accept those integers every time ?

    • Alex

      I’m not sure I understand your question. You’re asking how we prevent users from entering numbers too big for a given integer? In C++11, std::cin will do some overflow validation and both return false and set the fail bit if there is overflow.

      I’ll update one of the integer lessons shortly to add this information since it’s generally useful.

      • J3ANP3T3R

        Yep sort of like a way for C++ to ignore any input from the user that exceeds the limit imposed on that data type. without prompting a programming error. like if we wanted to get an INT input from the user but the user typed in 999999999999999999999999999999999999999 if i understood this correctly this will either generate an error or C++ will trim 999999999999999999999999999999999999999 to what will fit in INT without generating an error message all the while the user thought his data is accepted only to find out later on the database its just 9999999 something.

        thanks ^_^

  • Nick

    Potentially stupid question, but in the example:

    why is it necessary to indicate that

    is in

    but not

    . Is the namespace specification not necessary for type definitions?

    • Alex

      For historical reasons (because these types come from C99), many implementations of cstdint put the fixed-width integer types into the global namespace (as well as the std namespace).

      The more proper usage should be to prefix these with std::, as implementations are not required to put the types into the global namespace. I’ll update my examples.

  • Greg

    Thanks for the heads up on the 8-bit fixed integers acting like chars. They function as chars in the most recent version of Code::Blocks (16.01). Will probably save me a headache later on since I plan on using fixed integers exclusively.

  • nikos-13

    Hi Alex, I tried to execute the following program at codeblocks,

    #include <iostream>
    #include <cstdint>

    int main()
    {
        std::int16_t i(5); // direct initialization
        std::cout << i;
        return 0;
    }

    but this happened:

    // Copyright (C) 2007-2014 Free Software Foundation, Inc.
    //
    // This file is part of the GNU ISO C++ Library.  This library is free
    // software; you can redistribute it and/or modify it under the
    // terms of the GNU General Public License as published by the
    // Free Software Foundation; either version 3, or (at your option)
    // any later version.

    // This library is distributed in the hope that it will be useful,
    // but WITHOUT ANY WARRANTY; without even the implied warranty of
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    // GNU General Public License for more details.

    // Under Section 7 of GPL version 3, you are granted additional
    // permissions described in the GCC Runtime Library Exception, version
    // 3.1, as published by the Free Software Foundation.

    // You should have received a copy of the GNU General Public License and
    // a copy of the GCC Runtime Library Exception along with this program;
    // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
    // <http://www.gnu.org/licenses/>.

    /** @file bits/c++0x_warning.h
    *  This is an internal header file, included by other library headers.
    *  Do not attempt to use it directly. @headername{iosfwd}
    */

    #ifndef _CXX0X_WARNING_H
    #define _CXX0X_WARNING_H 1

    #if __cplusplus < 201103L
    #error This file requires compiler and library support for the \
    ISO C++ 2011 standard. This support is currently experimental, and must be \
    enabled with the -std=c++11 or -std=gnu++11 compiler options.
    #endif

    #endif

    What should I do to have fixed-width integers???

  • John

    Using MinGW Distro - nuwen.net I don’t need to include <cstdint> to use fixed-with integers (fwi). Does this means that the compiler follows the C++ 11 standard and the support for fwi is built in? Code example below.

    main.cpp

    Output
    i = P    P
    j = 81    81
    k = 82    82
    l = 83    83

    static_cast     i = 80    80
    wow         i = 80    80

    • Alex

      Not quite. So two things are happening here:
      1) Your compiler appears to be including support for the fixed-width integers for you.
      2) It’s unclear whether it’s doing this for C++11 compatibility or for C compatibility.

      If you intend to use the fixed-width integers in C++, you should #include cstdint explicitly. If this works, then your compiler supports this feature from C++11. If it doesn’t, then your compiler is providing this for backwards compatibility with C.

  • Matt

    Typo in third from last paragraph, first sentence:
    "Many modern programming language"

    …should be plural.

  • Joshua

    I dont know if I am learning or what. Should I reread the whole tutorial.

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter