Why ternary operator does not support blocks? - c

Why the ternary operator does not have blocks? In other words, why the following code does not work and reports error for {} braces?
int main()
{
int i = 1;
(i==1)?{printf("Hello\n")}:{printf("World\n")};
return 0;
}
EDIT
Perhaps the question is misunderstood. It was: why blocks are not supported? Why only single expression?
Why this is not allowed to work?
int main()
{
int i = 1;
(i==1)?{printf("Hello\n");printf("World\n");}:{printf("Bye\n");printf("World\n");};
return 0;
}
One reason could be that ternary are often used for conditional assignment on left side and blocks will have no such returns or it will get confusing with multiple statements inside block.

To quote C11 standard, chapter §6.5.15, the syntax of the conditional operator is
conditional-expression:
logical-OR-expression
logical-OR-expression ? expression : conditional-expression
Where, the second and third operands are expression, not statements.
Just to elaborate,
One of the following shall hold for the second and third operands:
— both operands have arithmetic type;
— both operands have the same structure or union type;
— both operands have void type;
— both operands are pointers to qualified or unqualified versions of compatible types;
— one operand is a pointer and the other is a null pointer constant; or
— one operand is a pointer to an object type and the other is a pointer to a qualified or
unqualified version of void.
Edit:
To answer the question
Why only single expression?
again, quoting the standard,
....the result is the value of the second or third operand (whichever is evaluated), converted to the type described below.
Block of statements, will not give a value. The evaluation of an expression can.

The ternary operator consists of expressions. There is no such a kind of expression that uses braces.
You can write simply
( i == 1 ) ? printf("Hello\n") : printf("World\n");
It seems that the only case when braces can be present in an expression is the use of a compound literal. For example
struct A { int x; int y; } a = { 1, 2 };
a = a.x < a.y ? ( struct A ){ a.y, a.x } : ( struct A ){ ++a.x, --a.y };
As for this statement
(i==1)?{printf("Hello\n");printf("World\n");}:{printf("Bye\n");printf("World\n");};
then it can be rewritten the following way using the comma operator
i == 1 ? ( printf("Hello\n"), printf("World\n") ) : ( printf("Bye\n"), printf("World\n") );
Or even like
i == 1 ? printf("Hello\n"), printf("World\n") : ( printf("Bye\n"), printf("World\n") );
Shortly answering your question if you need a code block then use the if-else statement instead of the ternary operator. Though the if-else statement may not be used in expressions. On the other hand it is desirable for readability of the code that expressions would not be too compound.
As any operator the ternary operator is used in expressions and returns some evaluated value. For example as an expression it can be used as initializer or in assignments.

The ternary operator expects an expression for each part, and {...} is not an expression, but a statement.
To expand on your edit, the result of a ternary operator is an expression (but not an lvalue as you suggest), and statement blocks can't evaluate to a value.
For example, this doesn't make sense:
int x = (i==1)?{printf("Hello\n");printf("World\n");}:{printf("Bye\n");printf("World\n");};
But you could do this:
int x = (i==1)?(printf("Hello\n"), printf("World\n")):(printf("Bye\n"), printf("World\n"));
In which case, the comma operator would cause the last value in each subexpression to be returned.

Operators in C language can only be used in expressions. There's no such thing as "block" in an expression. In C language blocks are elements of higher-level syntactic structure. Blocks exists at the level of statements. Expression can be used in a statement. But statement cannot become an expression (or be used inside an expression).
Your particular example can be rewritten in terms of expressions
i == 1 ?
printf("Hello\n"), printf("World\n") :
printf("Bye\n"), printf("World\n");
without any need for {}.
(See Uses of C comma operator for extra information)

Yes only one expression is possible in ternary operators..You have to use if-else for multiple statements. Ternary operators takes one expression only in each slot
although you can call two different functions in ternary operator
#include <stdio.h>
void a(){
printf("Hello\n");
printf("Hi\n");
}
void b(){
printf("Hi\n");
printf("Hello\n");
}
int main()
{
int i = 1;
(i == 1) ? a() : b();
return 0;
}

The ternary operator is not meant to be used as a control structure, meaning it's not meant to control execution of statements. It's simply a way to choose which of two or more expressions will be evaluated.
As Sourav Ghosh has shown, the syntax of a conditional expression simply does not allow the operands of the ?: operator to be statements.

This is not allowed because it makes no sense. The ternary operator is meant to return a value. What would that be for {} blocks?
And then also there is another construct if () { } else { } that already serves the same purpose that you are trying to give to ? :. Doesn't this here look much nicer than the code that you posted?
int main(void)
{
int i = 1;
if (i==1) {
printf("Hello\n");
printf("World\n");
} else {
printf("Bye\n");
printf("World\n");
};
return 0;
}

As others have noted, GCC allows statements to be used syntactically as expressions, but such a feature is not part of the C standard. Historically, the reason for this likely had to do with the fact that statements are allowed to declare variables, and many systems use the same stack to hold local variables and parameters as is used to hold temporary values used in expression evaluation. Allowing new variables to come into existence within the execution of a statement while still keeping old variables in view would add some complexity to the compiler [note that when a function is called within a new expression, new variables are created for that function, but the old values will be "out of view" until the called function returns and the new variables are destroyed].
That having been said, other features of C such as variable-length arrays require far more complexity than would the ability to embed statements in expressions, so the arguments in favor of that design are no longer as compelling as they were in the 1970s. Unfortunately, the fact that something was once a compelling reason not to include a feature in a language may cause it to forevermore be perceived that way, even if design considerations for today's compilers are nothing like those of the 1970s.

Why ternary operator does not support blocks?
For roughly the same reason that a bicycle does not support wings.
If you have two blocks of statements, and you want to execute one or the other based on a condition, there's a perfectly good way to do that: the if/else statement.
And if you have two expressions, and you want to evaluate one or the other based on a condition, that's what the ternary or ?: operator is for.
But asking the ?: operator to execute one or the other of two blocks of statements is asking it to do something it's not meant for. Continuing the jokey analogies, it's like asking, why can't a hammer drive screws?
This distinction — that if/else is for blocks of statements, and ?: is for expressions — flows out of C's fundamental distinction between expressions and statements. They're only partially integrated in C: you can turn any expression into a statement by putting a semicolon after it, but you can not, in general, use a statement as an expression. Why not? Well, partly because the syntax of the language doesn't permit it, and partly because there's no universal definition of what the value of a statement (or a block of statements) is.
Now, you can certainly imagine a language in which every statement has a well-defined value. In such a language, if/else and ?: would probably be fully interchangeable. And, in fact, some C compilers do implement this full integration of expressions and statements, as an extension — but it's an extension, not Standard C.

Related

Dictate order that operands are evaluated in c

The statement puts("a") + puts("b") is undefined.
This is because it is not specified in the C Standard whether these ought to be executed left to right or right to left so you could get
a
b
or
b
a
Is there a clean way to dictate the order of operations in an expression?
The only thing I can think of is to use a compound statement such as
({
int temp = puts("a");
temp += puts("b");
temp;
})
though this is non-portable and a little longer than I was hoping.
How could this best be achieved?
If you declare an int variable before the expression, you can force order portably with the comma operator while computing the sum inside an expression:
int temp;
...
(temp = puts("a"), temp + puts("b"))
As specified in the C Standard:
6.5.17 Comma operator
Syntax
expression:
assignment-expression
expression , assignment-expression
Semantics
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.
Note however that the value of the expression will not be very useful given the semantics of puts(), as commented by Jonathan Leffler.
The only way to force the order of evaluation is to use separate statements.
Compilers can use whatever order is deemed necessary. So for function calls f1() + f2() + f3(); any of one of those function calls could be called before the other. The only influence you can have on that statement is what to do with the returns from those functions. So in short, just use separate statements. Most likely for whatever you're doing, putting the calls in a loop should do fine.
Decent reference:
http://en.cppreference.com/w/c/language/eval_order

Assigning multiple integers separated by comma to an int in C - Why does that work? What for? [duplicate]

This question already has answers here:
C comma operator
(4 answers)
What does the comma operator , do?
(8 answers)
Closed 7 years ago.
I saw this in an exam and when I tried it out I was surprised. I tried it online and it works too. So I think it is the C language.
Why is that working? What is the use case for such an assignment syntax?
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
int i = (1,2,3,4,5);
printf("%d", i);
return 0;
}
These are not "multiple integers", but a comma operator. The whole parenthesised part is a single expression with each sub-expression (separated by commas) evaluated strictly from left to right. The results of all but the rightmost subexpression are ignored. The result of the whole expression is that of the last (rightmost) expression. Here it is the integer value 5.
Note that this operator is mostly used where only a single expression is allowed to add further side-effects. E.g. in a loop like:
int cnt = 0;
for ( const char *cp = "Hello" ; *cp != '\0' ; cp++, cnt++ ) ;
This counts the number of characters in a C-string, incrementing the pointer and cnt after each iteration. The results are ignored here.
So, this is in no way related to tuples or similar like in Python. There are actually no cases the usage of this operator is unavoidable and it should be used with caution — and some coding standards forbid its usage.
That's the comma operator at work. It evaluates the expression on its left-hand side, creates a sequence point, discards the value of the expression, then evaluates the expression on the right-hand side, and returns that as the value. When there are multiple expressions as in the example, then each is evaluated in turn and only the last is kept. With the sample, the compiler does the evaluation because every value is known at compile time. Note that the argument list to a function is not a use of the comma operator.
That isn't a valid use-case for the comma operator. What might be a more nearly valid use-case would be some operations with side-effects (such as function calls) that need to be sequenced and the final value assigned:
int i = (getchar(), getchar(), getchar());
This sets i to the third character in standard input, or EOF if there are not three characters left in the standard input to be read. Still not a realistic use-case, but better than assigning a list of constants.
In addition to the other answers, you need to watch for instances where a , is the comma operator as opposed to when it is a separator. For example, the following is invalid:
int i = 1,2,3,4,5;
In this case, the , is a separator between variable declarations. It declares i as an int and initializes it to 1, then it attempts to parse 2 as a variable name, which fails.
It works because you're using the "comma operator", which evaluates the subexpressions on the left and right, and has the value from the right-hand expression.
So in (1,2,3,4,5), 1 is evaluated and the result is discarded, then 2,3,4,5... in which (because of the next comma) 2 is evaluated and the result discarded, then 3,4,5... in which 3 is evaluated and discarded, then 4,5... in which 4 is evaluated and discarded, then 5 which becomes the result of the expression.
As for when it's useful, mainly as a shortcut when you need to evaluate several (sub)expressions for their side effects but aren't interested in their values (except maybe the last one). It's sometimes convenient in for loop expressions, such as when incrementing two variables:
for (i=0,j=1; j < len; i++,j++) {
..where it appears in both the initialization expression and the loop expression.
Why is that working?
Because its a valid C syntax. The comma in (1,2,3,4,5) are comma operator
C11: 6.5.17 Comma operator
Syntax
1 expression:
assignment-expression
expression , assignment-expression
Semantics
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.114)
What is the use case for such an assignment syntax?
See the example below
3 EXAMPLE As indicated by the syntax, the comma operator (as described in this subclause) cannot appear in contexts where a comma is used to separate items in a list (such as arguments to functions or lists of initializers). On the other hand, it can be used within a parenthesized expression or within the second
expression of a conditional operator in such contexts. In the function call
f(a, (t=3, t+2), c)
the function has three arguments, the second of which has the value 5.

Why is this version of logical AND in C not showing short-circuit behavior?

Yes, this is a homework question, but I've done my research and a fair amount of deep thought on the topic and can't figure this out. The question states that this piece of code does NOT exhibit short-circuit behavior and asks why. But it looks to me like it does exhibit short-circuit behavior, so can someone explain why it doesn't?
In C:
int sc_and(int a, int b) {
return a ? b : 0;
}
It looks to me that in the case that a is false, the program will not try to evaluate b at all, but I must be wrong. Why does the program even touch b in this case, when it doesn't have to?
This is a trick question. b is an input argument to the sc_and method, and so will always be evaluated. In other-words sc_and(a(), b()) will call a() and call b() (order not guaranteed), then call sc_and with the results of a(), b() which passes to a?b:0. It has nothing to do with the ternary operator itself, which would absolutely short-circuit.
UPDATE
With regards to why I called this a 'trick question': It's because of the lack of well-defined context for where to consider 'short circuiting' (at least as reproduced by the OP). Many persons, when given just a function definition, assume that the context of the question is asking about the body of the function; they often do not consider the function as an expression in and of itself. This is the 'trick' of the question; To remind you that in programming in general, but especially in languages like C-likes that often have many exceptions to rules, you can't do that. Example, if the question was asked as such:
Consider the following code. Will sc_and exibit short-circuit behavior when called from main:
int sc_and(int a, int b){
return a?b:0;
}
int a(){
cout<<"called a!"<<endl;
return 0;
}
int b(){
cout<<"called b!"<<endl;
return 1;
}
int main(char* argc, char** argv){
int x = sc_and(a(), b());
return 0;
}
It would be immediately clear that you're supposed to be thinking of sc_and as an operator in and of itself in your own domain-specific language, and evaluating if the call to sc_and exhibits short-circuit behavior like a regular && would. I would not consider that to be a trick question at all, because it's clear you're not supposed to focus on the ternary operator, and are instead supposed to focus on C/C++'s function-call mechanics (and, I would guess, lead nicely into a follow-up question to write an sc_and that does short-circuit, which would involve using a #define rather than a function).
Whether or not you call what the ternary operator itself does short-circuiting (or something else, like 'conditional evaluation') depends on your definition of short-circuiting, and you can read the various comments for thoughts on that. By mine it does, but it's not terribly relevant to the actual question or why I called it a 'trick'.
When the statement
bool x = a && b++; // a and b are of int type
executes, b++ will not be evaluated if the operand a evaluated to false (short circuit behavior). This means that the side-effect on b will not take place.
Now, look at the function:
bool and_fun(int a, int b)
{
return a && b;
}
and call this
bool x = and_fun(a, b++);
In this case, whether a is true or false, b++ will always be evaluated1 during function call and side effect on b will always take place.
Same is true for
int x = a ? b : 0; // Short circuit behavior
and
int sc_and (int a, int b) // No short circuit behavior.
{
return a ? b : 0;
}
1 Order of evaluation of function arguments are unspecified.
As already pointed out by others, no matter what gets pass into the function as the two arguments, it gets evaluated as it gets passed in. That is way before the tenary operation.
On the other hand, this
#define sc_and(a, b) \
((a) ?(b) :0)
would "short-circuit", as this macro does not imply a function call and with this no evaluation of a function's argument(s) is performed.
Edited to correct the errors noted in #cmasters comment.
In
int sc_and(int a, int b) {
return a ? b : 0;
}
... the returned expression does exhibit short-circuit evaluation, but the function call does not.
Try calling
sc_and (0, 1 / 0);
The function call evaluates 1 / 0, though it is never used, hence causing - probably - a divide by zero error.
Relevant excerpts from the (draft) ANSI C Standard are:
2.1.2.3 Program execution
...
In the abstract machine, all expressions are evaluated as specified by
the semantics. An actual implementation need not evaluate part of an
expression if it can deduce that its value is not used and that no
needed side effects are produced (including any caused by calling a
function or accessing a volatile object).
and
3.3.2.2 Function calls
....
Semantics
...
In preparing for the call to a function, the arguments are evaluated,
and each parameter is assigned the value of the corresponding
argument.
My guess is that each argument is evaluated as an expression, but that the argument list as a whole is not an expression, hence the non-SCE behaviour is mandatory.
As a splasher on the surface of the deep waters of the C standard, I'd appreciate a properly informed view on two aspects:
Does evaluating 1 / 0 produce undefined behaviour?
Is an argument list an expression? (I think not)
P.S.
Even you move to C++, and define sc_and as an inline function, you will not get SCE. If you define it as a C macro, as #alk does, you certainly will.
To clearly see ternary op short circuiting try changing the code slightly to use function pointers instead of integers:
int a() {
printf("I'm a() returning 0\n");
return 0;
}
int b() {
printf("And I'm b() returning 1 (not that it matters)\n");
return 1;
}
int sc_and(int (*a)(), int (*b)()) {
a() ? b() : 0;
}
int main() {
sc_and(a, b);
return 0;
}
And then compile it (even with almost NO optimization: -O0!). You will see b() is not executed if a() returns false.
% gcc -O0 tershort.c
% ./a.out
I'm a() returning 0
%
Here the generated assembly looks like:
call *%rdx <-- call a()
testl %eax, %eax <-- test result
je .L8 <-- skip if 0 (false)
movq -16(%rbp), %rdx
movl $0, %eax
call *%rdx <- calls b() only if not skipped
.L8:
So as others correctly pointed out the question trick is to make you focus on the ternary operator behaviour that DOES short circuit (call that 'conditional evaluation') instead of the parameter evaluation on call (call by value) that DOES NOT short circuit.
The C ternary operator can never short-circuit, because it only evaluates a single expression a (the condition), to determine a value given by expressions b and c, if any value might be returned.
The following code:
int ret = a ? b : c; // Here, b and c are expressions that return a value.
It's almost equivalent to the following code:
int ret;
if(a) {ret = b} else {ret = c}
The expression a may be formed by other operators like && or || that can short circuit because they may evaluate two expressions before returning a value, but that would not be considered as the ternary operator doing short-circuit but the operators used in the condition as it does in a regular if statement.
Update:
There is some debate about the ternary operator being a short-circuit operator. The argument says any operator that doesn't evaluate all it's operands does short-circuit according to #aruisdante in the comment below. If given this definition, then the ternary operator would be short-circuiting and in the case this is the original definition I agree. The problem is that the term "short-circuit" was originally used for a specific kind of operator that allowed this behavior and those are the logic/boolean operators, and the reason why are only those is what I'll try to explain.
Following the article Short-circuit Evaluation, the short-circuit evaluation is only referred to boolean operators implemented into the language in a way where knowing that the first operand will make the second irrelevant, this is, for the && operator being the first operand false, and for the || operator being the first operand true, the C11 spec also notes it in 6.5.13 Logical AND operator and 6.5.14 Logical OR operator.
This means that for the short-circuit behavior to be identified, you would expect to identify it in an operator that must evaluate all operands just like the boolean operators if the first operand doesn't make irrelevant the second. This is in line with what is written in another definition for the short-circuit in MathWorks under the "Logical short-circuiting" section, since short-circuiting comes from the logical operators.
As I've been trying to explain the C ternary operator, also called ternary if, only evaluates two of the operands, it evaluates the first one, and then evaluates a second one, either one of the two remaining depending on the value of the first one. It always does this, its not supposed to be evaluating all three in any situation, so there is no "short-circuit" in any case.
As always, if you see something is not right, please write a comment with an argument against this and not just a downvote, that just makes the SO experience worse, and I believe we can be a much better community that one that just downvotes answers one does not agree with.

Is it safe to use foo() && 0 in C?

Imagine i have the following piece of C-code where foo() produces a side effect and returns an integer:
if(bar) {
foo();
return 0;
}
Now, say I really like making my code compact, possibly at the reader's expense, and I change it into this:
if (bar)
return foo() && 0;
Can I be sure these two pieces of code will produce the same behavior, or would I risk the call to foo() not being executed due to possible compiler optimizations or something like that, thus not producing the desired side-effect?
NOTE: This is not a question about which piece of code is better, but whether the two pieces actually produce the same behavior in all cases. I think the majority (and I) can agree that the former piece of code should be used.
Yes, those two are the same. foo() will always be called (assuming bar is true).
The two forms you give are equivalent. The C11 standard (draft n1570) states,
6.5.13 Logical AND operator
...
Semantics
3 The && operator shall yield 1 if both of its operands compare unequal to 0;
otherwise, it yields 0. The result has type int.
4 Unlike the bitwise binary & operator, the && operator guarantees left-to-right
evaluation; if the second operand is evaluated, there is a sequence point between
the evaluations of the first and second operands. If the first operand compares
equal to 0, the second operand is not evaluated.
Similar language appeared in all C standards so far.
You should probably prefer using the comma operator here (return foo(), 0;) because:
It's shorter (one character versus two for the operator, and you can get away with removing the left space character when using a comma, for a total of two fewer characters).
It gives you more flexibility, as you can return non-scalar types (such as structs), and a wider range of integers than just 0 or 1.
It conveys the intent better: "Discard return value of foo() and return something else (0) instead".
Now if you do chance upon a compiler that deletes the call to foo(), then either the compiler managed to prove that foo() is a function with no visible side-effects, or more likely it has a serious bug and you should report it.
Why obfuscate your code in the latter?
Use the former.
Easier to read i.e. this is easier to understand
if(bar) {
foo();
return 0;
}
Or unless got a problem with job security

?: ternary conditional operator behaviour when leaving one expression empty

I was writing a console application that would try to "guess" a number by trial and error, it worked fine and all but it left me wondering about a certain part that I wrote absentmindedly,
The code is:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int x,i,a,cc;
for(;;){
scanf("%d",&x);
a=50;
i=100/a;
for(cc=0;;cc++)
{
if(x<a)
{
printf("%d was too big\n",a);
a=a-((100/(i<<=1))?:1);
}
else if (x>a)
{
printf("%d was too small\n",a);
a=a+((100/(i<<=1))?:1);
}
else
{
printf("%d was the right number\n-----------------%d---------------------\n",a,cc);
break;
}
}
}
return 0;
}
More specifically the part that confused me is
a=a+((100/(i<<=1))?:1);
//Code, code
a=a-((100/(i<<=1))?:1);
I used ((100/(i<<=1))?:1) to make sure that if 100/(i<<=1) returned 0 (or false) the whole expression would evaluate to 1 ((100/(i<<=1))?:***1***), and I left the part of the conditional that would work if it was true empty ((100/(i<<=1))? _this space_ :1), it seems to work correctly but is there any risk in leaving that part of the conditional empty?
This is a GNU C extension (see ?: wikipedia entry), so for portability you should explicitly state the second operand.
In the 'true' case, it is returning the result of the conditional.
The following statements are almost equivalent:
a = x ?: y;
a = x ? x : y;
The only difference is in the first statement, x is always evaluated once, whereas in the second, x will be evaluated twice if it is true. So the only difference is when evaluating x has side effects.
Either way, I'd consider this a subtle use of the syntax... and if you have any empathy for those maintaining your code, you should explicitly state the operand. :)
On the other hand, it's a nice little trick for a common use case.
This is a GCC extension to the C language. When nothing appears between ?:, then the value of the comparison is used in the true case.
The middle operand in a conditional expression may be omitted. Then if the first operand is nonzero, its value is the value of the conditional expression.
Therefore, the expression
    x ? : y
has the value of x if that is nonzero; otherwise, the value of y.
This example is perfectly equivalent to
    x ? x : y
In this simple case, the ability to omit the middle operand is not especially useful. When it becomes useful is when the first operand does, or may (if it is a macro argument), contain a side effect. Then repeating the operand in the middle would perform the side effect twice. Omitting the middle operand uses the value already computed without the undesirable effects of recomputing it.

Resources