sizeof operator in c

mohamad wael
9 min readAug 26, 2021

What is the sizeof operator?

The sizeof operator, returns the size of an expression, or of an object type in C. An expression is for example 1 + 2, an object is any region of memory, and a type is for example int. The value returned by the sizeof operator, is of type size_t, and its unit is byte.

sizeof( Type )
/* When using sizeof with an object type
such as an int, the parenthesis ()
must be used .*/

sizeof expression
sizeof( expression )
/* When the sizeof operator is used
with an expression, the parenthesis ()
can or cannot be used .*/

size_t is an unsigned integer type, which is defined in the stddef.h header. It can hold any value returned by the sizeof operator, and has a min value of 0, and a max value of the largest value, that can be returned by the sizeof operator. size_t can for example be defined as:

typedef unsigned long size_t;

The sizeof operator returns 1, meaning 1 byte, when used with the char, unsigned char, or signed char types.

#include <stdio.h>

int main( int argc, char * argv [ ] ){
printf( "sizeof( char ) is: %lu\n", sizeof( char ) );
/*output:
sizeof( char ) is: 1 */
return 0;}

The number of bits in a char, is defined in the limits.h header, using the macro CHAR_BIT.

#define CHAR_BIT 8

The following example illustrates, how to get the number of bits for other types.

#include <stdio.h>
/* include the stdio.h header, in
order to use printf, to print
formatted strings .*/

#include <limits.h>
/* include the limits.h header,
to use CHAR_BIT, which defines
the number of bits, that the
char type can have .*/
int main( int argc, char * argv[ ] )
{
printf( "sizeof( int ) is: %lu bytes\n", sizeof( int ));
/* output:
sizeof( int ) is: 4 bytes .*/

printf( "size of int in bits is: %lu bits\n", sizeof( int ) * CHAR_BIT );
/* output:
size of int in bits is: 32 bits .*/
return 0;}

sizeof and structures

When sizeof is used with a structure, it returns the size of the elements in this structure, with any padding. Padding will happen, when the size of the structure is not a multiple of the size of the largest element in this structure.

A structure is padded with bits, that don’t have any specific value, till it has a size which is a multiple of the largest element in this structure. Padding happens to have faster access to the structure elements, and because sometimes some cpu architecture don’t support access to non aligned memory.

#include <stdio.h>
/* include the stdio header
to use the printf
function .*/

struct aPaddedStruct{
char aChar;
// aChar has a size of 1
int anInt;
/* anInt has a size of 4
bytes .*/ };
/* The size of aPaddedStruct is 8
instead of 5, since the size of
the largest element in this struct
is 4 bytes .*/

int main( int argc , char * argv[ ] ){
printf( "sizeof( struct aPaddedStruct ) is: %lu",
sizeof( struct aPaddedStruct ));
// sizeof( struct aPaddedStruct ) is: 8
return 0; }

If the last element of a structure is an array, which size is not defined, then sizeof will return the size of the structure, without the array size.

#include<stdio.h>
/* include the stdio header,
to use the printf
function .*/

struct aStruct{
short aShort;
/* size of short is
2 bytes .*/
char aCharOne;
// size of char is 1
char aCharTwo;
// size of char is 1
int anIntArray[ ];
/* anIntArray doesn't have a size,
because it does not define the
number of elements it has.*/ };
// size of aStruct is 4

int main( int argc, char *argv[ ] ){
printf( "sizeof( aStruct ) is: %lu", sizeof( struct aStruct ));
/*output :
sizeof( aStruct ) is: 4 */
return 0; }

sizeof and unions

sizeof returns the size of the largest element in a union.

#include <stdio.h>
/* include the stdio header,
to use the printf
function .*/

union aUnion{
char aChar;
// size of char is 1
int anInt;
// size of int is 4
long double aLongDouble;
/*size of long double
is 16 .*/ };
/* union aUnion will have the
size of its largest element,
it is aLongDouble, which is
a long double, as such
it has a size of 16 .*/


int main( int argc, char * argv[ ] ){
printf( "sizeof( union aUnion ) is: %lu" ,sizeof( union aUnion ));
/* output:
sizeof( union aUnion ) is: 16 .*/
return 0;}

A compiler might add padding to a union, so that its size, will be a multiple of the size of the largest element, in this union. This is used to allow faster access, or because some cpu architecture, don't allow access to non aligned boundaries.

#include <stdio.h>
/* include the stdio header,
to use the printf
function .*/

struct _aStruct{
int anIntOne;
// size of an int is 4
short aShort;
// size of a short is 2
int anIntTwo;
/* size of an int is 4 .*/ };
/* The size of _aStruct is 12,
since it is padded to the size of its
largest element, which is an int .*/
union aUnion{
struct _aStruct aStruct;
// size of struct _aStruct is 12
long aLong;
/* size of long is 8 .*/ };
/* The size of the largest element
in this union is long. The
union is padded to the size of
its largest element, hence
it has a size of 16 .*/

int main( int argc, char * argv[ ] ){
printf( "The size of aUnion is: %lu\n",
sizeof( union aUnion ));
/*output:
the size of aUnion is: 16 */
return 0;}

sizeof and arrays

When using sizeof with an array, it will return the size of all the elements in the array.

#include <stdio.h>
/* include the stdio header,
to use the printf
function .*/


int main( int argc, char * argv[ ] ){

int anIntArray[ 22 ];
/* anIntArray has a size
of the size of
the int type, multiplied by 22.
so it has a size of 4 * 22 = 88
bytes .*/

printf( "sizeof( anIntArray ) is: %lu\n" , sizeof( anIntArray ));
// sizeof( anIntArray ) is: 88

char aCharArray[ 3 ];
/* aCharArray has a size
of the size of
the char type, multiplied by 3 .
so it has a size of 1 * 3 = 3
bytes .*/

printf( "sizeof( aCharArray ) is: %lu\n" , sizeof( aCharArray ));
// sizeof( aCharArray ) is: 3

return 0;}

sizeof can be used to calculate the number of elements in an array, by dividing the size of the array, by the size of an element in the array.

#include <stdio.h>
/* include the stdio header,
to use the printf
function .*/

int main( int argc, char * argv[ ] ){

short aShortArray[ 4 ];
/* aShortArray has a size of
the size of the short
type, multiplied by
4, so it has a size
of 2 * 4 = 8 .*/

printf( "Number of elements in the array is: %lu\n",
sizeof( aShortArray ) / sizeof( aShortArray[ 0 ] ));
/* sizeof( aShortArray ) is equal to sizeof( short ) * 4
sizeof( aShortArray[ 0 ] ) is equal to sizeof( short )
hence sizeof( aShortArray ) / sizeof( aShortArray[ 0 ] ) = number of elements in the array
output:
Number of elements in the array is: 4 .*/
return 0;}

sizeof and pointers

A pointer is simply an address which is stored in memory, as such it has a size. The sizeof operator, can be used to get the size of a pointer. There is no defined size of a pointer in C, it is defined by the implementation, usually on a 32 bits machine, a pointer has a size of 32 bits, and on a 64 bits machine, a pointer has a size of 64 bits.

#include <stdio.h>
/* include the stdio header,
to use the printf
function .*/

int main(int argc, char * argv[ ]){
printf("sizeof( void * ) is %lu\n", sizeof (void * ));
// sizeof( void * ) is 8

printf( "sizeof( char * ) is %lu\n", sizeof( char * ));
// sizeof( char * ) is 8

return 0;}

sizeof and other object types

An object is just a memory region, so it has an allocated size. The object types in C are:

  • integer types, such as int, short, enum…
  • floating types, such as float, double, long double.
  • structures.
  • unions.
  • arrays.
  • pointers.
  • atomic types.
#include <stdio.h>
/* include the stdio header, to
use the printf function .*/

#include <stdatomic.h>
/* include the stdatomic header,
to access the atomic types .*/

enum Binary{
zero,
one };
/* define the enum Binary,
an enum is an integer of
the type int .*/

struct Boolean{
char _cBool;
unsigned char _iBool;
} true = {'T', 1}, false = {'F', 0};
/* define a Boolean structure.
the Boolean structure defines that
a boolean, has a char and an int
representation.
Two variables were initialized
from this structure, true and
false .*/


union BooleanOrBinary {
enum Binary binary;
struct Boolean boolean;};
/* Define a union BooleanOrBinary, to
store a boolean value ,
as either of type struct Boolean
or as of type enum Binary .*/
/* Print the sizeof object types
on a given machine.
The sizeof a char is always 1.
The sizeof object types are a
multiple of the sizeof a char.
The size of objects types
might vary from one machine
to another .*/
int main( ){
printf( "sizeof( char ) is : %lu byte\n", sizeof( char ));
// sizeof( char ) is: 1 byte

printf( "sizeof( short ) is : %lu byte\n", sizeof( short ));
// sizeof( short ) is: 2 byte

printf( "sizeof( int ) is: %lu byte\n", sizeof( int ));
// sizeof( int ) is: 4 byte

printf("sizeof( long int ) is: %lu byte\n", sizeof( long int ));
// sizeof( long int ) is: 8 byte

printf( "sizeof( long long int ) is: %lu byte\n", sizeof( long long int ));
// sizeof(long long int) is : 8 byte

printf( "sizeof( float ) is: %lu byte\n", sizeof( float ));
// sizeof( float ) is: 4 byte

printf( "sizeof( double ) is: %lu byte\n", sizeof( double ));
// sizeof( double ) is: 8 byte

printf( "sizeof( long double ) is: %lu byte\n", sizeof( long double ));
// sizeof( long double ) is: 16 byte

printf( "sizeof( enum binary ) is: %lu byte\n", sizeof( enum Binary ));
// sizeof( enum binary ) is: 4 byte

printf( "sizeof( struct Boolean ) is : %lu byte\n", sizeof( struct Boolean ));
// sizeof( struct Boolean ) is: 2 byte

printf( "sizeof( union BooleanOrBinary ) is: %lu byte\n",
sizeof( union BooleanOrBinary ));
// sizeof( union BooleanOrBinary ) is: 4 byte

printf( "sizeof( void * ) is %lu byte\n", sizeof( void * ));
// sizeof( void * ) is 8 byte

printf( "sizeof( int[ 1 ] ) is: %lu byte\n", sizeof( int[ 1 ] ));
// sizeof( int[ 1 ] ) is: 4 byte

printf( "sizeof( atomic_int_fast32_t ) is: %lu byte\n",
sizeof( atomic_int_fast32_t ));
// sizeof( atomic_int_fast32_t ) is: 4 byte
return 0; }

sizeof and expressions

sizeof expression 
sizeof( expression )

An expression is simply a combination of operands and operators, whatever these operand or operators are. When using the sizeof operator with an expression, the parenthesis () can be used or skipped .

#include <stdio.h>
/* include the stdio header,
to use the printf
function .*/


int sum( int x, int y ){
/* return the sum of x and y */
return x + y; }


int main( int argc, char * argv[ ] ){

int anInt = 1;
printf( "sizeof anInt is: %lu \n", sizeof anInt );
// sizeof anInt is: 4

double aDouble = 3.0;
printf( "sizeof aDouble is: %lu \n", sizeof aDouble );
// sizeof aDouble is: 8

printf( "sizeof( aDouble + anInt ) is: %lu \n",
sizeof( aDouble + anInt ));
// sizeof( aDouble + anInt ) is: 8

printf( "sizeof( 3.0f + 1 ) is: %lu \n", sizeof( 3.0f + 1 ));
/* 3.0f is a float
3.0f + 1 = 4.0f
4.0f is a float
sizeof( float ) is 4
Output:
sizeof (3.0 + 1) is: 4 .*/

printf( "sizeof sum( 1, 5 ) is: %lu \n", sizeof sum( 1, 5 ));
// sizeof sum( 1, 5 ) is: 4

printf( "sizeof 100 is: %lu \n", sizeof 100 );
// sizeof 100 is: 4

return 0;}

sizeof cannot be applied?

The sizeof operator, cannot be applied to a non object type, such as a function, or to an incomplete type. An incomplete type, is a type which is declared but not yet defined, or a type which doesn't have a size, such as the void type.

struct incompleteTypeStruct;
/* struct incompleteTypeStruct is declared
but is not yet defined , as such it
is an incomplete type .*/

enum incompleteTypeEnum;
/* enum incompleteTypeEnum is declared
but is not yet defined, as such it is
an incomplete type .*/

int anIntarray[ ];
/* anIntarray size is not defined, as
such it is an incomplete type .*/

int main( int argc, char * argv[ ] ){
sizeof( struct incompleteTypeStruct );
sizeof( enum incompleteTypeEnum );
sizeof( anIntarray );
sizeof( void );
/* These statements will cause
an error, since they are trying to
get the size of incomplete types .*/

return 0;}

Originally published at https://twiserandom.com on August 26, 2021.

--

--