-1

I define an int like this:

int a;

When I want to lookup the size of this int, I have to use the format specifier %ld like this:

printf("int size is %ld\n", sizeof(a));

When I use %d as the format specifier, I get the following error:

foo.c:7:10: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
    printf("int size is %d\n", sizeof(a));

The question is, why is the result of sizeof() defined as long unsigned int when the parameter of the function is an int?

Thorsten Scherf
  • 871
  • 2
  • 7
  • 6

5 Answers5

7

The type of sizeof(anything) is size_t, which is some unsigned integral constant. To print it, you should be using %zu.

Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
6

According to the C Standard (6.5.3.4 The sizeof and alignof operators)

5 The value of the result of both operators is implementation-defined, and its type (an unsigned integer type) is size_t, defined in <stddef.h> (and other headers).

and (7.19 Common definitions <stddef.h>)

size_t which is the unsigned integer type of the result of the sizeof operator;

and (7.21.6.1 The fprintf function)

z Specifies that a following d, i, o, u, x, or X conversion specifier applies to a size_t....

Thus it would be more correctly to write

printf( "int size is %zu\n", sizeof( a ) );
                     ^^^

It is not important what type of an object the operator sizeof is applied to. It returns the number of bytes occupied by an object of the given type and the returned number has type size_t.

Your compiler issues a warning because in your system type size_t is defined like unsigned long int but you are using signed int. It seems does not issue a warning when you use format specifier %ld because the rank of the signed long int type is equal to the rank of the unsigned long int type that corresponds to size_t.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
4

"when the parameter of the function is an int?"

First off, sizeof is an operator, not a function.

Second, why do you think its result type should be the same as its argument type? What if you want to get the size of a struct? or an array? or a pointer? How would it be supposed to yield the size of a struct as a struct? It just doesn't make sense.

It yields a size, so the type of its result is size_t, that you should print using %zu.

2

sizeof gives the number of storage units taken up by the operand. The result type is size_t, which is an unsigned type wide enough to represent the size of the largest object the system is capable of storing. The type of the operand doesn't affect the type of the result.

With C89 compilers, you can print a size_t value with %ld and cast the argument to unsigned long:

 printf( "sizeof x = %ld\n", (unsigned long) sizeof x );

With C99 and later compilers, use %zu:

 printf( "sizeof x = %zu\n", sizeof x );
John Bode
  • 119,563
  • 19
  • 122
  • 198
  • I like your answer best because it doesn't drag in unnecessary C99 junk; it shows the original, highly portable way to do it, If you know that `x` is basic type, you can cast its size to `int`, and use `%d`, or to `unsigned` and use `%u`. Only with arrays, and perhaps very large structures, would you have to worry that the size isn't representable in unsigned int. – Kaz Aug 16 '15 at 19:16
0

%zu is not portable; it requires a C99 library. For instance, MinGW:

$ cat zu.c
#include <stdio.h>

int main(void)
{
  printf("%zu\n", sizeof (int));
  return 0;
}

$ gcc zu.c -o zu

$ ./zu.exe
zu

Oops! The characters zu printed literally, and the size argument was ignored.

For printing types which you know are reasonably small, cast the size to int or unsigned, and use the %d or %u conversion specifier:

printf("sizeof int == %d\n", (int) sizeof (int));

If there is any possibility that the size of an object might not fit into type int, try unsigned long int:

printf("sizeof int == %lu\n", (unsigned long) sizeof object);

This is probably only necessary on systems with a small int, like 16 bits, such that int only goes up to 32767 and unsigned int to 65535, and yet there can be objects whose sizes exceed these values.

If you're sure that the program needs only to be portable to targets that support C99, then %zu it is.

Kaz
  • 55,781
  • 9
  • 100
  • 149
  • %lu is just as non-portable as %zu, in a different way. If you count how many implementation has larger a 'size_t' than `unslgned long`, and how many implementations doesn't support `%zu`, I highly suspect the former is fewer. – user3528438 Aug 16 '15 at 21:00
  • @user3528438 If the *value* of the `sizeof` expression fits into an `unsigned long` (i.e. lies within the range [0, `ULONG_MAX`)), then everything is cool. It doesn't matter if the type `size_t` itself is wider than `unsigned long`. This issue is adequately covered in the answer. – Kaz Aug 16 '15 at 22:53
  • IMHO, whenever some variable/type of of unknown wideness occurs, best to print with widest well defined unsigned known type and a cast: `printf("sizeof int == %llu\n", (unsigned long long) sizeof object);`. – chux - Reinstate Monica Aug 17 '15 at 01:37
  • @chux That's totally irrational if you know that the type is, say, some built-in arithmetic type, and anything but a gargantuan array. – Kaz Aug 17 '15 at 03:06