The sizeof Operator in C and C++

Textbooks rarely make good use of the sizeof operator in C (and C++). The syntax is

sizeof ( type )

and

sizeof variable

That is, in order to get the size of a variable, including an array, the parenthesis are not necessary. I personally find them a visual distraction, unless of course the operand is a type, like sizeof ( int ).

Let’s look at a concrete example of using sizeof without parenthesis. In this example, we’re preparing an error message for display on screen.

char buffer[ 1024 ]; /* Arbitrary size of the buffer. */
snprintf( buffer, sizeof buffer, "Unable to initialize SDL: %s", SDL_GetError() );

Because we’re using sizeof buffer in the snprintf() call we don’t have to worry about mistakes, or out of sync constants, and we don’t have to #define BUFFER_SIZE 1024 to use the same size in both definition of the buffer and call to snprintf().

Note to Windows programmers. The snprintf() function isn’t documented to always terminate the string with zero until Visual Studio 2015 and Windows 10. Programmers on the Windows platform might want to add an explicit zero termination to account for older compilers and systems. That can be done with buffer[ sizeof buffer - 1 ] = '\0'.

The trick here is that we defined buffer as an array. If we had instead used malloc() to allocate the buffer, we would have to add the size of the buffer explicitly, like so,

char *buffer = malloc( 1024 );
if ( !buffer ) exit( 1 );
snprintf( buffer, 1024, "Unable to initialize SDL: %s", SDL_GetError() );

and we would have to explicitly check the return value from malloc() as is written about at length in why it is important to check what the malloc function returned. If we had instead used sizeof buffer here, we’d have gotten 4 on a 32bit system, and 8 on a 64bit system — which is totally not the value we need.

The snprintf() function returns how many characters have been or would be printed. In our case we don’t care if the message the user receives gets truncated, so we don’t check its return value.

It is worth noting that when a character literal is used, it matters whether the literal is declared as a pointer or array. That is, given

  char *foo   = "Error string.",
        bar[] = "Another error string.";

then sizeof foo will give us 4 on 32bit system, 8 on a 64bit system, while sizeof bar is 22 or the length of the string including the terminating zero byte.

Literals

The sizeof operator applies to literals also without parenthesis, and it’s instructive to test it on some literal combinations on a given system. For example, this program

#include <stdio.h>

int main( int argc, char *argv[] )
{
  printf( "sizeof 0 = %zu\n",       sizeof 0 );     // int
  printf( "sizeof 0l = %zu\n",      sizeof 0l );    // long
  printf( "sizeof 0ll = %zu\n",     sizeof 0ll );   // long long
  printf( "sizeof NULL = %zu\n",    sizeof NULL );  // pointer
  printf( "sizeof 0.0 = %zu\n",     sizeof 0.0 );   // double
  printf( "sizeof 0.0f = %zu\n",    sizeof 0.0f );  // float
  printf( "sizeof \"foo\" = %zu\n", sizeof "foo" ); // string size including zero terminator
  return 0;
}

run an a 64bit Linux and compiled with clang, gives

sizeof 0 = 4
sizeof 0l = 8
sizeof 0ll = 8
sizeof NULL = 8
sizeof 0.0 = 8
sizeof 0.0f = 4
sizeof "foo" = 4

and none of that should be surprising.

Contact

The author can be reached at johann@myrkraverk.com.

Updates

Added the section on literals.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: