20

I have this program

#include <stdio.h>
int main()
{
   char arr[100];
   printf("%d", (int)sizeof(0,arr));
}

This prints 4 when compiled as a C file and prints 100 as a C++ file. Why? I am using gcc.

user724619
  • 287
  • 1
  • 5
  • Note that the only reason to use the comma operator is to produce a side effect of evaluation, but the expression of a `sizeof` operation is not evaluated. – Potatoswatter Apr 23 '11 at 19:36
  • A declared array is decayed to a pointer in *every* occasion in C, *except* when it appears as operand of `sizeof` or the `&`-operator. In your case, that's not the case, hence it's converted to a pointer. In C++, the array is converted only if needed. – Johannes Schaub - litb Apr 23 '11 at 20:39
  • An excellent example of why compiling C with a C++ compiler is a misguided practice. – R.. GitHub STOP HELPING ICE Apr 23 '11 at 21:39
  • 1
    Using the comma operator like this (or in almost any other way) is a misguided practice. – Alan Apr 24 '11 at 00:12
  • 1
    The real question is "[why are you trying to mix two languages in a single source file?](http://jquelin.blogspot.com/search/label/polyglot)" – pmg Apr 24 '11 at 11:33

2 Answers2

34

In C the result of the right hand operand of the comma operator has a type and value. In C a comma operator does not yield an lvalue. So there is an lvalue to rvalue conversion resulting in decay of array type to pointer type. So in C what you get is the result of sizeof(char*).

In C++ the result of a comma expression is an lvalue. There is no such conversion[as in C] and what you get is the sizeof(arr) i.e 100

Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
  • 1
    That's a pretty sweet answer, I had no idea that behaviour existed in C. – Puppy Apr 23 '11 at 19:47
  • Even if the comma operator yielded an lvalue in C, it would still print `100`. Because the right operand of the comma operator in his case is a non-lvalue `char*`. – Johannes Schaub - litb Apr 23 '11 at 20:40
  • Yes, the array-decay rules specify that this decay happens as soon as the array name is used except as an operand of `&` or `sizeof`. Since it's being used as an operand of `,` (the comma operator), it has already decayed, regardless of whether `,` preserves lvalues. – R.. GitHub STOP HELPING ICE Apr 23 '11 at 21:39
  • The answer doesn't explain why the result is different in C when `sizeof` is directly applied, as that's an expression also. The explanation is: there is a specific exception in the conversion rules for `sizeof`. That exception does not exist in C++, no doubt because the conversion rules are different. – DigitalRoss Apr 23 '11 at 23:56
3

sizeof is an operator not a function

So, you are executing the comma operator, which returns the right operand as its result.

In C++, this is a reference, so it's still an array and has its full size.

In C, in an expression (anything with an operator) normally the type array of x is converted to pointer to x. But there is a specific exception for two operators: sizeof and &.

So it matters if sizeof gets there first or not, because of the exception to the conversion rules. (See C99 section 6.3.2.1.)

You can see this another way, and here the program returns the same thing in C and C++.

#include <stdio.h>
int main(void) {
  char arr[100];

  printf("%d\n", (int)sizeof arr);
  printf("%d\n", (int)sizeof(arr + 0));
  return 0;
}

result on my Mac:

100
8

† 6.3.2.1(3) Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue.

DigitalRoss
  • 143,651
  • 25
  • 248
  • 329
  • "in C++ this is a reference" - you mean "this is an lvalue"; expressions never have reference type – M.M Oct 18 '17 at 10:36