Output data type of sizeof() operator
Asked Answered
I

1

11

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).

Isocracy answered 31/1, 2019 at 15:15 Comment(15)
"Why 'long unsigned int' but not 'int'?" What sense would negative value, returned from sizeof make?Watchman
Actually "%ld" is also wrong. The sizeof operator returns a value of type size_t, and to print it with printf (and family) you should use "%zu". Or since you also tagged this question with the very different C++ language, just use std::cout << sizeof(something).Bridges
@AdhamzhonShukurov The return type of sizeof operator is size_t which is unsigned and int is signed by default.Violaviolable
Possible duplicate of How sizeof operator works in C?Cedric
This has been asked a zillion times. C gold badges: why is it still open???Cedric
What's the correct way to use printf to print a size_t?, Output data type of sizeof() operatorDuctile
Possible duplicate of What's the correct way to use printf to print a size_t?Ductile
size_t appears to be long unsigned int on your system, but it doesn't have to. Can be unsigned short or unsigned int or whatever, as long as it can represent the size of objects on that platformDuctile
@Cedric is it still duplicate?Isocracy
@Ductile can you consider my question again?Isocracy
myuint32 is an uint32_t which must be printed using PRIu32. Remember int is not always 32 bits, and printing an unsigned type with signed format specifier is still UB. printf format specifiers for uint32_t and size_tDuctile
@Ductile But up to 2147483647 uint32_t and 32 bit integer decoded the same way. + I am asking why it does not even give a result.Isocracy
why %d does not do the same (i.e. decode the last 32 bits of content of size_t variable as it was int?) C doesn't work that way. Type sizes are not fixed and vararg functions doesn't know what size a parameter is. On platforms where those are on stack then if you specify a different type different from what you give it then you can mess up the stack when printf pops a different number of bytes for that argument. As said, use the correct specifier and don't wonder why it works here and not thereDuctile
@Ductile Thanks for the answer, but my aim is to use C together with custom HDL designed hardware, that is why it is really important to me to wonder about these things.Isocracy
@Ductile By the way duplicate linked question does not seem to be enough to completely answer my question, I would be glad if you remove it (of course if you agree with me).Isocracy
W
27

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));
Whipple answered 31/1, 2019 at 15:17 Comment(8)
I downvoted since as a C gold badge I'd expect you to close this question as the duplicate it is rather than answering.Cedric
@Cedric It's not always easy to find one unless you have a specific one in mind. Given that this one has a title that better reflects the question, is more upvoted, and has an answer with a quote from the standard, I'm reversing the dup.Whipple
I found the duplicate by searching for "printf format sizeof". First answer. I disagree with you but not strongly enough to do anything.Cedric
"I'm going to close the other question as a dupe of this one because I wrote the answer here". If you think your answer adds something over the answer to the other question, move your answer there. This is not right.Stripe
Given that the questions (and their answers) are substantially identical, it might be best to ask a mod to merge them. (I also kind of agree with @CrisLuengo that you probably shouldn't have dupehammered that question yourself. Even if it was objectively the right call -- which I'm not sure about -- it still looks like an attempt to game the system for rep and visibility.)Comyns
@Whipple Thanks for the good answer, it partially answered my question, but can you update it accordingly and give more information (I edited the question).Isocracy
@AdhamzhonShukurov No, you added another question to your original question. this is frowned upon on Stack Overflow. Prefer asking a new question.Cedric
@AdhamzhonShukurov Since your edit was asking for clarification on the last part of your original question, I've updated to address.Whipple

© 2022 - 2024 — McMap. All rights reserved.