Can someone explain why sizeof() returns these values with unary operators?

Viewed 108
#include <stdio.h>

int main() {
    int a;
    char b;
    short int c;
    double d;
    printf("%d %d %d %d\n", sizeof(a), sizeof(b), sizeof(c), sizeof(d));
    printf("%d %d %d %d\n", sizeof(+a), sizeof(+b), sizeof(+c), sizeof(+d));
    printf("%d %d %d %d\n", sizeof(-a), sizeof(-b), sizeof(-c), sizeof(-d));
    return 0;
}

32-bit compiler output:

4 1 2 8
4 4 4 8
4 4 4 8

The output is the same if I change the the sign inside the sizeof(), like sizeof(-a). I want to know why this happens. Are the + and - operators promoting the datatypes?

3 Answers

Yes, the unary + and - operators integer promote small integer types to int. C17 6.5.3.3:

The result of the unary + operator is the value of its (promoted) operand. The integer promotions are performed on the operand, and the result has the promoted type.

The result of the unary - operator is the negative of its (promoted) operand. The integer promotions are performed on the operand, and the result has the promoted type.

For details about integer promotion, see Implicit type promotion rules.


You can play around with _Generic to find out the actual type of any expression:

#include<stdio.h>

#define type(x) _Generic((x),    \
  int:   puts(#x " is int"),     \
  short: puts(#x " is short"),   \
  char:  puts(#x " is char") );  \

int main (void)
{
  int a;
  char b;
  short int c;
  
  type(a); type(+a);
  type(b); type(+b);
  type(c); type(+c);
}

Output:

a is int
+a is int
b is char
+b is int
c is short
+c is int

That is exactly it. When calculations are made (i.e. for instance + or -) the shorter integer formats are promoted to the base size, which is int, which is 4 bytes long.

Small integers types are promoted to int or unsigned int when used as arguments in simple arithmetic expressions. Hence sizeof(b) is 1, the size of a char, but sizeof(+b) is 4, the size of an int on your platform.

Note however that printf expects an int argument for the %d conversion specification. sizeof() has type size_t, an unsigned type potentially different from unsigned int. You should either use %zu or cast the sizeof() expressions as (int).

Here is a sample program for illustration:

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

#define typeof(X)  _Generic((X),                                        \
                   long double: "long double",                          \
                   double: "double",                                    \
                   float: "float",                                      \
                   unsigned long long int: "unsigned long long int",    \
                   long long int: "long long int",                      \
                   unsigned long int: "unsigned long int",              \
                   long int: "long int",                                \
                   unsigned int: "unsigned int",                        \
                   int: "int",                                          \
                   unsigned short: "unsigned short",                    \
                   short: "short",                                      \
                   unsigned char: "unsigned char",                      \
                   signed char: "signed char",                          \
                   char: "char",                                        \
                   bool: "bool",                                        \
                   __int128_t: "__int128_t",                            \
                   __uint128_t: "__uint128_t",                          \
                   default: "other")

int main() {
    int a;
    char b;
    short int c;

#define TEST(x)  printf("%8s has type %s and size %zu\n", #x, typeof(x), sizeof(x))
    TEST(a);
    TEST(+a);
    TEST(b);
    TEST(+b);
    TEST(c);
    TEST(+c);
    TEST('0');
    TEST(*"");
    TEST(0);
    TEST(0L);
    TEST(0LL);
    TEST(0.F);
    TEST(0.);
    TEST(0.L);
    TEST(sizeof(a));

    return 0;
}

Output on 64-bit OS/X:

       a has type int and size 4
      +a has type int and size 4
       b has type char and size 1
      +b has type int and size 4
       c has type short and size 2
      +c has type int and size 4
     '0' has type int and size 4
     *"" has type char and size 1
       0 has type int and size 4
      0L has type long int and size 8
     0LL has type long long int and size 8
     0.F has type float and size 4
      0. has type double and size 8
     0.L has type long double and size 16
sizeof(a) has type unsigned long int and size 8
Related