12

I wrote the code about sizeof operator. If I write something like:

#include <stdio.h>

int main() {
    char a[20];
    printf("%zu\n", sizeof(a));
    return 0;
}

Output:

20 // Ok, it's fine

But, If I use the comma operator like this:

#include <stdio.h>

int main() {
    char a[20];
    char b;
    printf("%zu\n", sizeof(b, a));
    return 0;
}

Output:

8 // Why the output 8?

So, I have a questions:

  • Why does compiler give an output 8 in second example?
  • What is the behavior of comma operator into sizeof() operator?
Zoe
  • 27,060
  • 21
  • 118
  • 148
msc
  • 33,420
  • 29
  • 119
  • 214

4 Answers4

12

The comma operator has no special meaning to sizeof.

sizeof(b, a) examines the complete expression (b, a), works out the resultant type, and computes the size of that type without actually evaluating (b , a). As noted by chqrlie in comments, the () are part of the expression for which the size (of the result) is evaluated.

In this case, b is a char and a is an array. If the expression b, a was to be evaluated, b would be evaluated first, the result discarded. Then a would converted to a pointer (char *) with value equal to &a[0] which would be the result of the expression (b, a).

Since the result of b, a is of type char *, sizeof(b,a) is equal to sizeof (char *). That is an implementation defined value but, for your compiler, has a value of 8 (which probably means the code is being built as a 64-bit application).

Peter
  • 35,646
  • 4
  • 32
  • 74
  • 3
    *`sizeof(b, a)` examines the complete expression `b, a`*... Technically, `sizeof(b, a)` examines the complete expression `(b, a)`. But interestingly and confusingly enough, `sizeof((a))` would still produce a value of `20`. – chqrlie Oct 18 '17 at 10:11
  • `sizeof(b, a) examines the complete expression b, a` I think the parenthesis are the first evaluated and then sizeof will evaluate the result. Isn't it ? – Michi Oct 18 '17 at 10:37
  • @Michi parentheses (in this context) are not an operator – M.M Oct 18 '17 at 10:41
  • @M.M I never said that :). I was speaking about what happens inside those parenthesis and this is first evaluated and only after SIZEOF evaluates the result. Or I'm wrong. – Michi Oct 18 '17 at 10:49
  • @M.M Any way [this was my point](https://ideone.com/ijUcKz), when I said that first will be the content of those parenthesis evaluated and then `sizeof` evaluates the result. – Michi Oct 18 '17 at 10:59
  • 1
    True- `sizeof(b,a)` evaluates the size of the result from the expression `(b,a)`. Syntactically `sizeof(int)` requires the `()` around the type name (so `sizeof int` is invalid) while `sizeof expression` does not require `()` and the `()`, if used, are part of the expression. I'll edit to reflect that shortly. – Peter Oct 18 '17 at 12:22
  • @Peter Thanks for answer. – msc Oct 18 '17 at 13:38
11

In most cases, arrays decay into pointers. So the type of b,a with a comma operator is a char* (not a char[20] anymore). And pointers are 8 bytes on your machine.

BTW, I think that using sizeof on some comma operator is really confusing to the reader. I recommend using sizeof on simple expressions or on types.

(and I just discovered this is one of the tricky differences between C and C++; see this explanation)

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • 3
    Reference is C11 6.3.2.1/3: "Except when it is the operand of the `sizeof` operator, the `_Alignof` 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." – M.M Oct 18 '17 at 09:45
  • This is a wonky issue, but the fact that there is the comma operator and a sequence point between evaluation of `b` and `a` may cause conflict with that reference C11 6.5.17/2 Comma operator. I don't know the answer, but it seems that `a` would be converted to a pointer if `b` is evaluated as a void pointer injecting a sequence point. – David C. Rankin Oct 18 '17 at 09:55
  • 3
    @DavidC.Rankin neither b nor a is evaluated, since they are part of the operand of sizeof. Sequence points have nothing to do with this – M.M Oct 18 '17 at 09:57
  • C11 6.5.17/3 says a comma operator cannot appear as arguments to a function. Now `sizeof` isn't per se a function. I'll certainly defer to your interpretation here. I don't know, but want to make sure I clearly understand -- and with the competing comments and answer -- I do not :( And all I can do is read, the standard says "*The left operand of a comma operator is evaluated as a void expression*"... "*Then the right operand is evaluated;*" – David C. Rankin Oct 18 '17 at 10:00
  • 1
    *"this explanation"* is sitting on an exact duplicate. Why didn't you vote to close? – StoryTeller - Unslander Monica Oct 18 '17 at 10:41
4

C language is an lvalue-discarding language. Comma operator in C does not yield an lvalue and does not preserve "arrayness" of arrays. This means that when right-hand side operand is an array, it is immediately subjected to array-to-pointer conversion. For this reason in C the result of your comma operator is an rvalue of type char *. This is what you apply your sizeof to. And this is why you get 8 as the result, which is pointer size on your platform.

C++ language is an lvalue-preserving language. The right-hand operand of comma operator in C++ is not subjected to lvalue-to-rvalue conversion and, in case the operand is an array, it maintains its lvalueness and its array type. In C++ the result of your comma operator is an lvalue of type char[20]. This is what you apply your sizeof to. And this is why you get 20 as the result.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • The whole story here is because of those parenthesis and has nothing to do with sizeof operator. like I said in my comment, if you do `int a = (1,2,3);` it works but if you do `int a = 1,2,3;` it will not because of the missing of those parenthesis. I think you know way. – Michi Oct 18 '17 at 10:35
  • @Michi: It is true that "parenthesis has nothing to do with sizeof operator". But I don't see the importance of this in this context. The code compiles - that's given. – AnT stands with Russia Oct 18 '17 at 10:42
  • the whole point here is that people should stop treating SIZEOF operator as a function and they can avoid a thing like this. They are concentrate only on SIZEOF and not what exactly is on the right side. – Michi Oct 18 '17 at 10:44
  • @Michi: "Avoid"? Avoid what exactly? I don't see anything in this topic intended to persuade anyone to "avoid" anything. The question is rather technical and neutral. The author is well-aware of the fact that `,` in this context is a *comma operator*, not function argument separator. – AnT stands with Russia Oct 18 '17 at 10:46
  • Wow, didn't know about that difference between C and C++. Learned something today :-) – cmaster - reinstate monica Oct 19 '17 at 11:10
1

sizeof determines the size by the type of it's operand. In sizeof(a), a will not decay to pointer to it's first element and the type of a will be char[20]. While in sizeof(b, a), a is the right operand of comma operator and in this context it will decay to pointer to it's first element and the type of the expression b , a would be char *. Therefore, sizeof(b, a) will return size of char * data type.

In C++, result of , operator is an lvalue (unlike in C where it yields an rvalue). In that case sizeof(b, a) will return the size of array a.

haccks
  • 104,019
  • 25
  • 176
  • 264