Uses of C Comma Operator

What does the comma operator , do?

The expression:

(expression1,  expression2)

First expression1 is evaluated, then expression2 is evaluated, and the value of expression2 is returned for the whole expression.

Uses of C comma operator

C language (as well as C++) is historically a mix of two completely different programming styles, which one can refer to as "statement programming" and "expression programming". As you know, every procedural programming language normally supports such fundamental constructs as sequencing and branching (see Structured Programming). These fundamental constructs are present in C/C++ languages in two forms: one for statement programming, another for expression programming.

For example, when you write your program in terms of statements, you might use a sequence of statements separated by ;. When you want to do some branching, you use if statements. You can also use cycles and other kinds of control transfer statements.

In expression programming the same constructs are available to you as well. This is actually where , operator comes into play. Operator , is nothing else than a separator of sequential expressions in C, i.e. operator , in expression programming serves the same role as ; does in statement programming. Branching in expression programming is done through ?: operator and, alternatively, through short-circuit evaluation properties of && and || operators. (Expression programming has no cycles though. And to replace them with recursion you'd have to apply statement programming.)

For example, the following code

a = rand();
++a;
b = rand();
c = a + b / 2;
if (a < c - 5)
d = a;
else
d = b;

which is an example of traditional statement programming, can be re-written in terms of expression programming as

a = rand(), ++a, b = rand(), c = a + b / 2, a < c - 5 ? d = a : d = b;

or as

a = rand(), ++a, b = rand(), c = a + b / 2, d = a < c - 5 ? a : b;

or

d = (a = rand(), ++a, b = rand(), c = a + b / 2, a < c - 5 ? a : b);

or

a = rand(), ++a, b = rand(), c = a + b / 2, (a < c - 5 && (d = a, 1)) || (d = b);

Needless to say, in practice statement programming usually produces much more readable C/C++ code, so we normally use expression programming in very well measured and restricted amounts. But in many cases it comes handy. And the line between what is acceptable and what is not is to a large degree a matter of personal preference and the ability to recognize and read established idioms.

As an additional note: the very design of the language is obviously tailored towards statements. Statements can freely invoke expressions, but expressions can't invoke statements (aside from calling pre-defined functions). This situation is changed in a rather interesting way in GCC compiler, which supports so called "statement expressions" as an extension (symmetrical to "expression statements" in standard C). "Statement expressions" allow user to directly insert statement-based code into expressions, just like they can insert expression-based code into statements in standard C.

As another additional note: in C++ language functor-based programming plays an important role, which can be seen as another form of "expression programming". According to the current trends in C++ design, it might be considered preferable over traditional statement programming in many situations.

What is the proper use of the comma operator?

In your example it serves no reason at all. It is on occasion useful when written as

if(cond)
perror("an error occured"), exit(1) ;

-- then you don't need curly braces. But it's an invitation to disaster.

The comma operator is to put two or more expressions in a position where the reference only allows one. In your case, there is no need to use it; in other cases, such as in a while loop, it may be useful:

while (a = b, c < d)
...

where the actual "evaluation" of the while loop is governed solely on the last expression.

Comma operator in c

Can any one explain how output is 2?

In the statement

a = (1, 2), 3;   

, used is a comma operator.
Due to higher operator precedence of = operator than that of , operator, the expression operand (1, 2) will bind to = as

(a = (1, 2)), 3;  

In case of comma operator, the left operand of a comma operator is evaluated to a void expression, then the right operand is evaluated and the result has the value and type of the right operand.

There are two comma operators here. For the first comma operator in the expression (1, 2), 1 will be evaluated to void expression and then 2 will be evaluated and will be assigned to a.

Now side effect to a has been taken place and therefore the right operand of second comma operator 3 will be evaluated and the value of the expression (a = (1, 2)), 3 will be 3.

In C and C++, is an expression using the comma operator like a = b, ++a; undefined?

Case 3 is well defined.

First, let's look at how the expression is parsed:

a = b + a, a++

The comma operator , has the lowest precedence, followed by the assignment operator =, the addition operator + and the postincrement operator ++. So with the implicit parenthesis it is parsed as:

(a = (b + a)), (a++)

From here, section 6.5.17 of the C standard regarding the comma operator , says the following:

2 The left operand of a comma operator is evaluated as a void expression; there is a sequence point between its
evaluation and that of the right operand.
Then the right
operand is evaluated; the result has its type and value

Section 5.14 p1 of the C++11 standard has similar language:

A pair of expressions separated by a comma is evaluated left-to-right;
the left expression is a discarded- value expression.
Every value computation and side effect associated with the left
expression is sequenced before every value computation and side effect
associated with the right expression.
The type and value of the result
are the type and value of the right operand; the result is of the same
value category as its right operand, and is a bit-field if its right
operand is a glvalue and a bit-field.

Because of the sequence point, a = b + a is guaranteed to be fully evaluated before a++ in the expression a = b + a, a++.

Regarding free(foo), foo = bar, this also guarantees that foo is free'ed before a new value is assigned.

Is it good practice to use the comma operator?

It can be useful in the condition of while() loops:

while (update_thing(&foo), foo != 0) {
/* ... */
}

This avoids having to duplicate the update_thing() line while still maintaining the exit condition within the while() controlling expression, where you expect to find it. It also plays nicely with continue;.

It's also useful in writing complex macros that evaluate to a value.

The comma operator in a function argument

In your case,

  foo (x, (y=47, x), z);

is functionally similar as

  foo (x, x, z);

As per the property of comma operator, the LHS operand is evaluated and the result is discarded, then the RHS operand is evaluated and that's the result.

For sake of completion, quoting the C11, chapter §6.5.17

The left operand of a comma operator is evaluated as a void expression; there is a
sequence point between its evaluation and that of the right operand. Then the right
operand is evaluated; the result has its type and value.

Point to note: the variable y will be updated, as the LHS operand is evaluated as a void expression, but has no effect on this funcion call. In case, the y is a global variable and used in foo() function, it will see an initial value of 47.

That said, to answer

how is the parameter pushed on the stack

is very very implementation (architecture) dependent. C does not specify any order for function argument passing and some architecture may event not use "stack" for function argument passing, at all!!

Comma Operator in subscript operator?

It's important to recognize the difference between comma as an expression operator and comma as a separator between grammatical terms of some kind. They use the same punctuation, but they don't have the same meaning.

Within the {} of a braced-init-list, individual terms are separated by commas. So {1,2,3,45,5} is a sequence of terms. That's a comma-as-separator.

However, within a general expression, the comma acts as an expression operator. When a comma is an expression operator between two expression terms, it means to evaluate the left expression, discard its result, then evaluate the right expression, which is the result of the total expression.

Within a [], a comma is not a separator in C++17. Therefore, it acts as an expression operator. a[2,3] means to evaluate 2, discard it, then evaluate 3. So the index used will be 3.

C++20 deprecates a comma expression as the direct expression used in a []. It does this so that future versions of the C++ standard will have the freedom to make commas within [] become comma separators rather than comma operators. That is, [2, 3] makes 2 and 3 the parameters to a call to an overloaded operator[].

This is similar to how the parameters to a function use the separator comma. So if you need to use the operator comma on two expressions within a function call, you have to wrap them in (): func(1, (2, 3)). This function takes two parameters, with the second one being the result of the comma operator applied to its terms.

Using the comma operator when defining a macro

melpomene provided an example. Another example, although you could argue whether it's good or bad, is if you want to use the macro in a loop header.

#define MACRO(X) (X--, X>0)

int x=5;
while(MACRO(x)) {
// Do stuff
}

This example is definitely not the best in the world, but the point is that it would not work if you used semicolons instead to separate the expressions, no matter how you encapsulate them.



Related Topics



Leave a reply



Submit