Search

4.3 — Object sizes and the sizeof operator

Object sizes

As you learned in the lesson 4.1 -- Introduction to fundamental data types, memory on modern machines is typically organized into byte-sized units, with each byte of memory having a unique address. Up to this point, it has been useful to think of memory as a bunch of cubbyholes or mailboxes where we can put and retrieve information, and variables as names for accessing those cubbyholes or mailboxes.

However, this analogy is not quite correct in one regard -- most objects actually take up more than 1 byte of memory. A single object may use 2, 4, 8, or even more consecutive memory addresses. The amount of memory that an object uses is based on its data type.

Because we typically access memory through variable names (and not directly via memory addresses), the compiler is able to hide the details of how many bytes a given object uses from us. When we access some variable x, the compiler knows how many bytes of data to retrieve (based on the type of variable x), and can handle that task for us.

Even so, there are several reasons it is useful to know how much memory an object uses.

First, the more memory an object uses, the more information it can hold.

A single bit can hold 2 possible values, a 0, or a 1:

bit 0
0
1

2 bits can hold 4 possible values:

bit 0 bit 1
0 0
0 1
1 0
1 1

3 bits can hold 8 possible values:

bit 0 bit 1 bit 2
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1

To generalize, an object with n bits (where n is an integer) can hold 2n (2 to the power of n, also commonly written 2^n) unique values. Therefore, with an 8-bit byte, a byte-sized object can hold 28 (256) different values. An object that uses 2 bytes can hold 2^16 (65536) different values!

Thus, the size of the object puts a limit on the amount of unique values it can store -- objects that utilize more bytes can store a larger number of unique values. We will explore this further when we talk more about integers.

Second, computers have a finite amount of free memory. Every time we define an object, a small portion of that free memory is used for as long as the object is in existence. Because modern computers have a lot of memory, this impact is usually negligible. However, for programs that need a large amount of objects or data (e.g. a game that is rendering millions of polygons), the difference between using 1 byte and 8 byte objects can be significant.

Key insight

New programmers often focus too much on optimizing their code to use as little memory as possible. In most cases, this makes a negligible difference. Focus on writing maintainable code, and optimize only when and where the benefit will be substantive.

Fundamental data type sizes

The obvious next question is “how much memory do variables of different data types take?”. You may be surprised to find that the size of a given data type is dependent on the compiler and/or the computer architecture!

C++ only guarantees that each fundamental data types will have a minimum size:

Category Type Minimum Size Note
boolean bool 1 byte
character char 1 byte Always exactly 1 byte
wchar_t 1 byte
char16_t 2 bytes C++11 type
char32_t 4 bytes C++11 type
integer short 2 bytes
int 2 bytes
long 4 bytes
long long 8 bytes C99/C++11 type
floating point float 4 bytes
double 8 bytes
long double 8 bytes

However, the actual size of the variables may be different on your machine (particularly int, which is more often 4 bytes).

Best practice

For maximum compatibility, you shouldn’t assume that variables are larger than the specified minimum size.

Objects of fundamental data types are generally extremely fast.

The sizeof operator

In order to determine the size of data types on a particular machine, C++ provides an operator named sizeof. The sizeof operator is a unary operator that takes either a type or a variable, and returns its size in bytes. You can compile and run the following program to find out how large some of your data types are:

Here is the output from the author’s x64 machine, using Visual Studio:

bool:           1 bytes
char:           1 bytes
wchar_t:        2 bytes
char16_t:       2 bytes
char32_t:       4 bytes
short:          2 bytes
int:            4 bytes
long:           4 bytes
long long:      8 bytes
float:          4 bytes
double:         8 bytes
long double:    8 bytes

Your results may vary if you are using a different type of machine, or a different compiler. Note that you can not use the sizeof operator on the void type, since it has no size (doing so will cause a compile error).

For advanced readers

If you’re wondering what ‘\t’ is in the above program, it’s a special symbol that inserts a tab (in the example, we’re using it to align the output columns). We will cover ‘\t’ and other special symbols in lesson 4.11 -- Chars.

You can also use the sizeof operator on a variable name:

x is 4 bytes

Fundamental data type performance

On modern machines, objects of the fundamental data types are fast, so performance while using these types should generally not be a concern.

As an aside...

You might assume that types that use less memory would be faster than types that use more memory. This is not always true. CPUs are often optimized to process data of a certain size (e.g. 32 bits), and types that match that size may be processed quicker. On such a machine, a 32-bit int could be faster than a 16-bit short or an 8-bit char.


4.4 -- Signed integers
Index
4.2 -- Void

264 comments to 4.3 — Object sizes and the sizeof operator

  • Danger

    bool:           1 bytes
    char:           1 bytes
    wchar_t:        1 bytes
    char16_t:       1 bytes
    char32_t:       1 bytes
    short:          1 bytes
    int:            1 bytes
    long:           1 bytes
    long long:      1 bytes
    float:          1 bytes
    double:         1 bytes
    long double:    1 bytes

    why did i get this?

  • SuperNoob

    Tell me is it possible to write highly portable non-trivial code in c++? I ask this because sizeof(int) <= sizeof(long). Pardon me if I missed something.

    • nascardriver

      As long as you're not using system APIs, C++ is portable. If you need an integer to have a minimum width, use a guaranteed-width integer `std::int_*_t`.

  • SuperNoob

    The size of the integer types (int and long int) varies from system to system, right? (e.g. non-windows system)

  • vicky

    HI!
    I have one query.
    In my machine checked size of int and long, both showing 4 bytes.
    size of int:   4 bytes
    size of long:  4 bytes.

    if both have same size and used for integer, then what is the difference between these.
    Please give some example

  • Harshit Bajpai

    I have a doubt regarding wrapping string in single quotes. It gives a different result

    Output
    bool:            1 bytes

    receive a compilation warning -

    Why is this happening?

    • Slash

      Examples below give exactly the same output.

      Double quotes are used for strings:

      Single quotes are used for individual characters:

    • Sahil

      Using the ' ' you are telling the compiler that the following literal is of type char, thus it can only hold a single alphabet (1 byte) but you are entering a string literal which requires multiple bytes of storage and thus you get a compiler error saying that what you entered is too long for its type.

      The point being, use single quotes for character literal and double quotes for string literals.

  • J34NP3T3R

    just wondering
    in the example above where "int x{};" gives x a minimum size of 4 bytes ( and since its minimum then i would assume it can go above that number ) .
    when or how does the integer x exceeds the minimum ?
    does it depend on the value that will be stored to that variable later ?

    thank you

    • Sahil

      No, the size of any variable depends only on the compiler and your device, and the largest value that you can store in an int will depend on its size not the other way around.

  • Coz

    If char is only 1 byte, how can it hold a NULL which is 4 bytes? I'm guessing instead of "NULL" being stored it actually causes the compiler to clear the variable.

    char:           1 bytes
    char x:         1 bytes
    char x:         C

    NULL:           4 bytes

    char:           1 bytes
    char y:         1 bytes
    char y:

    • Coz

      I think I figured it out. In 4.11, "Char is used to store values that are interpreted as an ASCII character." NULL is an character similar to any letter or number. But that also brings up something else I was wondering about. If you asign a char variable a value, it stores it in a memory location. I don't understand if that happens with a NULL. Does it store NULL or causes an execution that clears the memory location? If it causes an execution, then a variable type is not just for storage. (I'm sure I am over thinking this.)

  • ChihWei

    "An object that uses 2 bytes can hold 2^16 (65536) different values!"
    This is a typo right?

    • Cristopher Klingensmith

      No, 1 byte is equal to 8 bits. Since the formula is 2^n (where n=number of bits) 2 bytes would be 2^16 because 2 bytes is 2 sets of 8 bits.

  • tran duc phong

    hello alex.
    To generalize, an object with n bits (where n is an integer) can hold 2n (2 to the power of n, also commonly written 2^n) unique values. Therefore, with an 8-bit byte, a byte-sized object can hold 28 (256) different values. An object that uses 2 bytes can hold 2^16 (65536) different values!
    1: as mentioned above
    then 4 types will have 4 ^ 32 bits, right? because 1 bype would have 8 bits and if there were 4 bytes would be 32 bits and doing the math would be 4 ^ 32 different values?
    2: And also as your statement, 1bit contains 2 values 1 or 0 if so 4 bits will display 4 ^ 8 different values?
    i am wondering how to do your calculation if possible give me examples of 4 bype and 4 bit calculation. thanks;

    • nascardriver

      (number of values) = (number of options) ^ (number of digits)
      For a 4 bit binary number, you have
      number of options: 2 (A bit is either 0 or 1)
      number of digits: 4
      number of values = 2^4 = 16

      A 4 byte wide type, has 4*8=32 bits, so it has 2^32 different values.

      This math isn't specific to binary.
      In decimal, there are 10 options per digit, so for a 3 digit number there are 10^3=1000 different values (0 to 999).

  • nascardriver

    `long`, `short`, etc. are modifiers that apply to the given type (By default, `int`). Each "long" in "long long" is a keyword, but "long long" isn't a keyword, it's 2 modifiers applied to `int`. This becomes more apparent when you mix the modified around

    is all the same

  • Raysen

    Hi! I'm having a blast to learn through the site, thank you so much for maintaining this!

    I have a question: in Chapter 1.7 (Keywords and naming identifiers) we learn about all the reserved keywords in the C++ language, and the rules of how to name the identifiers. In this list, we see that all the keywords are composed of a single word; some of them instead by the unition of two words connected by a _ .

    Now in this chapter we are introduced to two new keywords, "long long" and "double long" (which were not shown in the previous list!) that have a whitespace instead.

    How does that work? It seems abnormal and somehow against the syntax rules we have learned so far. I would expect them to be a long_long and double_long instead, no?

    • nascardriver

      `long`, `short`, etc. are modifiers that apply to the given type (By default, `int`). Each "long" in "long long" is a keyword, but "long long" isn't a keyword, it's 2 modifiers applied to `int`. This becomes more apparent when you mix the modified around

      is all the same

Leave a Comment

Put all code inside code tags: [code]your code here[/code]