3

I know that expressions like x++ or function calls don't get evaluated in the sizeof operator.

When I ran the below code, I got 4 8 8 as output. Can somebody explain to me what is actually happening on lines 6,7,8?

#include <stdio.h>
int main()
{
  int x=10;
  double y=10.0;
  printf("%d ",sizeof (x=x+y));    
  printf("%d ",sizeof (y=x+y));     
  printf("%d ",sizeof (x+y));
  return 0;
}

I figured out that if an expression contains an assignment operator = implicitly (like pre-increment) or explicitly (like x=x+y) , then the expression doesn't get evaluated in the sizeof operator.

Am I right?

Boann
  • 48,794
  • 16
  • 117
  • 146
ClassHacker
  • 394
  • 3
  • 11
  • 2
    A double may be a different size than an int. You are seeing the size of the type of variable that the expression is. The first is sizeof(int) while the second and third are sizeof(double) – drescherjm Aug 18 '20 at 13:55
  • What are the sizes of `int` and `double` in your platform? – Sourav Ghosh Aug 18 '20 at 13:56
  • I know that the sizeof (double) is 8 bytes and sizeof (int) is 4 bytes. – ClassHacker Aug 18 '20 at 13:56
  • 2
    Note that `%d` is the wrong format specifier for `size_t`, which is the type returned from `sizeof()`. The correct format specifier is `%zu`. – Andrew Henle Aug 18 '20 at 13:59
  • Tip: a good well enabled compiler will warn about type mis-match with `printf("%d ",sizeof (x+y));` This suggest you are compiling without all warnings enabled. Save time. Enable more warnings. – chux - Reinstate Monica Aug 18 '20 at 14:06
  • 3
    C or C++. Pick one. Since you `#include `, it seems your question is about C (and I thus removed the C++ tag). The `sizeof` operator works on the *type* of the expression, and the types of those expressions in your example are (subtly) **different** for C and C++. That is one of the reasons why we generally frown on questions tagged for both languages. – DevSolar Aug 18 '20 at 14:07
  • 1
    The answer you are looking for is _the usual arithmetic conversions_, see [Implicit type promotion rules](https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules). – Lundin Aug 18 '20 at 14:10

3 Answers3

9

sizeof operator operates on the datatype of the argument. In your code

  • expression (x=x+y) yields a type int, same as x
  • expression (y=x+y) yields a type double, same as y
  • expression x+y yields a type double, as per usual arithmetic conversion rules.

The sizes are calculated based on this.

In your platform, it's likely that sizeof(int) is 4 and sizeof(double) is 8, so you're seeing corresponding output.

That said, sizeof yields a result of type size_t, you must use %zu format specifier to print the result.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • 2
    Technically, I think the expressions yield types `int&`, `double&`, and `double`. `sizeof` gives the same results of course. – cigien Aug 18 '20 at 13:58
  • 2
    @cigien why `&`? – Sourav Ghosh Aug 18 '20 at 14:00
  • I believe operator = – drescherjm Aug 18 '20 at 14:00
  • 1
    Because the type returned by `operator=` is an l-value reference. – cigien Aug 18 '20 at 14:00
  • I would clarify that `sizeof(x=x+y)` is the same as `sizeof(x)`. – François Andrieux Aug 18 '20 at 14:01
  • @cigien I don't think that you can look at it that way for built-in types, you just get the lvalue directly. Though it behaves equivalently. Like dereferencing a `T*` is a `T` and not a `T&`. In any case, `sizeof(T) == sizeof(T&)`. You can't get the size of a reference type, you always get the size of the referred type instead. – François Andrieux Aug 18 '20 at 14:02
  • @FrançoisAndrieux I agree about the sizeof. But if it's not an l-value reference, then how does chaining `x=y=z` work even for built-in types? – cigien Aug 18 '20 at 14:05
  • 2
    Ah, the CPP part. Obviously. – Sourav Ghosh Aug 18 '20 at 14:07
  • @cigien It just evaluates to the same lvalue as the assigned-to operand. Consider that these operators are inherited from C, where there are no references. – François Andrieux Aug 18 '20 at 14:08
  • 1
    Well, now the c++ tag has been removed, so the difference is moot :p – cigien Aug 18 '20 at 14:09
  • @rustyx What confused me about the linked example is why `decltype(x)` doesn't also print `int&`. Turns out the difference between the two outputs is that `decltype` behaves differently when given an identifier than when given any other kind of expression. If you add parenthesis around `x` (`decltype((x))`) you get the uniform behavior that `decltype` treats all lvalue expressions as rvalue references. – François Andrieux Aug 18 '20 at 14:36
  • @rustyx That is also an artifact of `decltype`. It always adds a reference in that case even if the type isn't a reference. The confusion is that lvalue is a value category and lvalue reference is a type. Value categories and types have a little bit of overlap but are generally distinct concepts. The only way to represent value category as a type is to encode it in a reference with either rvalue references or lvalue references which is why `decltype` adds it. Otherwise there is no way to categorize the value category of an expression as a type. – François Andrieux Aug 18 '20 at 14:51
3

sizeof evaluates the type.

x is an int and seems to have the size of 4 bytes on your system.

y is a double and seems to have the size of 8 bytes on your system.

sizeof (x+y) will evaluate to the largest of the two, thereby double and 8 bytes.

x=x+y is is still an int as there will be a conversion to int type from the double x+y.

Thereby sizeof (x=x+y) is 4 bytes.

y=x+y is still an double as x+y is of the type double.

Thereby sizeof (y=x+y) is 8 bytes.

Robin Hellmers
  • 214
  • 1
  • 11
  • 2
    `x=x+y` does not contain a conversion to `int` from the `double` `y`. In `x+y`, `x` is converted to `double`. Then `x+y` is a `double`, and that is converted to `int` for the assignment. (All as if the expression would be evaluated.) – Eric Postpischil Aug 18 '20 at 14:07
-2

Expressions are evaluated, just results of those evaluations differ:

x=x+y

can be readed as:

int = float + int

What happens is, that result is calculated and then turncated to int and therefore you get the result 4: sizeof(int) = 4.

Second line is simmilar but with float.

On the last line you calculate sizeof (float + int) which is equal to sizeof(float) = 8.

Nikola
  • 125
  • 1
  • 8