Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Output data type of sizeof() operator

I am using Ubuntu 16.04.5 and GCC version 5.4.0.

I was playing with sizeof() operator, wrote the code below:

#include <stdio.h>

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

        long int mylint = 31331313131.1313;

        printf("size of long int is %d\n", sizeof(mylint));
        printf("size of long int is %d\n", sizeof(long int));

        return 0;
}

I tried to compile using gcc -o ... ... command and was expecting:

size of long int is 8
size of long int is 8

But I got the following error:

fl_double_lint.c: In function ‘main’:
fl_double_lint.c:11:9: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]

  printf("size of long int is %d\n", sizeof(mylint));
         ^
fl_double_lint.c:12:9: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
  printf("size of long int is %d\n", sizeof(long int));

When I use %ld instead it works as expected. Why sizeof() is not working with %d? (Why 'long unsigned int' but not 'int'?)

Edit: I know that many questions were asked regarding output of sizeof() operator (as suggested in comments). However, they do not answer the question of why using %d does not work (i.e. does not give any result). I know it is not correct format, but whenever we have a char type variable using %d we can get equivalent int result, this is also the case for short, uint8_t, uint16_t, uint32_t (generally for types with equal or less than 32 bit). The following code works:

#include <stdio.h>
#include <stdint.h>

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

        char mychar = 'd';
        uint32_t myuint32 = 32;
        uint16_t myuint16 = 16;
        uint8_t myuint8 = 8;
        short myshort = 26945;
        int myint = 100;

        printf("integer equivalent of mychar is %d\n", mychar);
        printf("integer equivalent of myuint8 is %d\n", myuint8);
        printf("integer equivalent of myuint16 is %d\n", myuint16);
        printf("integer equivalent of myuint32 is %d\n", myuint32);
        printf("character equivalent of myint is %c\n", myint);
        printf("integer equivalent of myshort is %d\n", myshort);


        return 0;
}

The result is:

integer equivalent of mychar is 100
integer equivalent of myuint8 is 8
integer equivalent of myuint16 is 16
integer equivalent of myuint32 is 32
character equivalent of myint is d
integer equivalent of myshort is 26945

And now I discovered that %d does not work for any variable that needs larger than 32 bit to be stored. After considering this question I have some idea about implementation dependence of size_t, maybe in my system it was unsigned long (%ld also giving the result proves it). So maybe if size_t was an unsigned int in my system I would get a result, is it true?

As it can be seen from the code above, %c decodes the last 8 bits of int as a character, why %d does not do the same (i.e. decode the last 32 bits of content of size_t variable as it was int? I believe if it would do so we could get the same result for small enough numbers, and this was what I meant when I initially asked the question).

like image 913
Adhamzhon Shukurov Avatar asked Jan 31 '19 15:01

Adhamzhon Shukurov


People also ask

What is the output of sizeof?

When sizeof() is used with the data types, it simply returns the amount of memory allocated to that data type. The output can be different on different machines like a 32-bit system can show different output while a 64-bit system can show different of same data types.

What is the datatype of sizeof?

sizeof can be applied to any data-type, including primitive types such as integer and floating-point types, pointer types, or compound datatypes such as Structure, union etc. sizeof() operator is used in different way according to the operand type.

What is sizeof () operator?

sizeof(int); The sizeof operator applied to a type name yields the amount of memory that can be used by an object of that type, including any internal or trailing padding. Using the sizeof operator with a fixed-point decimal type results in the total number of bytes that are occupied by the decimal type.

What is the return type for the sizeof operator?

The sizeof operator is used to get the size of types or variable in bytes. Returns an unsigned integer type of at least 16 bit. It's used to get portability.


1 Answers

The sizeof operator evaluates to a value of type size_t. This type is unsigned and typically larger than an int, which is why you get the warning.

Using the wrong format specifier to printf invokes undefined behavior. You can get away with this however for types smaller than int due to the rules of integer promotions in section 6.3.1.1p2 of the C standard:

The following may be used in an expression wherever an int or unsigned int may be used:

  • An object or expression with an integer type (other than int or unsigned int ) whose integer conversion rank is less than or equal to the rank of int and unsigned int .
  • A bit-field of type _Bool , int , signed int ,or unsigned int .

If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int ; otherwise, it is converted to an unsigned int . These are called the integer promotions . All other types are unchanged by the integer promotions.

So as long this doesn't result in a change from unsigned to signed, types smaller than int can be printed with %d.

The proper type modifier for size_t is %zu, as per section 7.21.6.1p7 of the C standard regarding length modifiers for the fprintf function (and by extension, printf):

z

Specifies that a following d , i , o , u , x ,or X conversion specifier applies to a size_t or the corresponding signed integer type argument; or that a following n conversion specifier applies to a pointer to a signed integer type corresponding to size_t argument.

So what you want is:

printf("size of long int is %zu\n", sizeof(mylint));
like image 155
dbush Avatar answered Oct 20 '22 00:10

dbush