Related
I saw this code:
if (cond) {
perror("an error occurred"), exit(1);
}
Why would you do that? Why not just:
if (cond) {
perror("an error occurred");
exit(1);
}
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.
Legitimate cases of the comma operator are rare, but they do exist. One example is when you want to have something happen inside of a conditional evaluation. For instance:
std::wstring example;
auto it = example.begin();
while (it = std::find(it, example.end(), L'\\'), it != example.end())
{
// Do something to each backslash in `example`
}
It can also be used in places where you can only place a single expression, but want two things to happen. For instance, the following loop increments x and decrements y in the for loop's third component:
int x = 0;
int y = some_number;
for(; x < y; ++x, --y)
{
// Do something which uses a converging x and y
}
Don't go looking for uses of it, but if it is appropriate, don't be afraid to use it, and don't be thrown for a loop if you see someone else using it. If you have two things which have no reason not to be separate statements, make them separate statements instead of using the comma operator.
The main use of the comma operator is obfuscation; it permits doing two
things where the reader only expects one. One of the most frequent
uses—adding side effects to a condition, falls under this
category. There are a few cases which might be considered valid,
however:
The one which was used to present it in K&R: incrementing two
variables in a for loop. In modern code, this might occur in a
function like std::transform, or std::copy, where an output iterator
is incremented symultaneously with the input iterator. (More often, of
course, these functions will contain a while loop, with the
incrementations in separate statements at the end of the loop. In such
cases, there's no point in using a comma rather than two statements.)
Another case which comes to mind is data validation of input parameters
in an initializer list:
MyClass::MyClass( T const& param )
: member( (validate( param ), param) )
{
}
(This assumes that validate( param ) will throw an exception if
something is wrong.) This use isn't particularly attractive, especially
as it needs the extra parentheses, but there aren't many alternatives.
Finally, I've sometimes seen the convention:
ScopedLock( myMutex ), protectedFunction();
, which avoids having to invent a name for the ScopedLock. To tell
the truth, I don't like it, but I have seen it used, and the alternative
of adding extra braces to ensure that the ScopedLock is immediately
destructed isn't very pretty either.
This can be better understood by taking some examples:
First:
Consider an expression:
x = ++j;
But for time being, if we need to assign a temporarily debug value, then we can write.
x = DEBUG_VALUE, ++j;
Second:
Comma , operators are frequently used in for() -loop e.g.:
for(i = 0, j = 10; i < N; j--, i++)
// ^ ^ here we can't use ;
Third:
One more example(actually one may find doing this interesting):
if (x = 16 / 4), if remainder is zero then print x = x - 1;
if (x = 16 / 5), if remainder is zero then print x = x + 1;
It can also be done in a single step;
if(x = n / d, n % d) // == x = n / d; if(n % d)
printf("Remainder not zero, x + 1 = %d", (x + 1));
else
printf("Remainder is zero, x - 1 = %d", (x - 1));
PS: It may also be interesting to know that sometimes it is disastrous to use , operator. For example in the question Strtok usage, code not working, by mistake, OP forgot to write name of the function and instead of writing tokens = strtok(NULL, ",'");, he wrote tokens = (NULL, ",'"); and he was not getting compilation error --but its a valid expression that tokens = ",'"; caused an infinite loop in his program.
The comma operator allows grouping expression where one is expected.
For example it can be useful in some case :
// In a loop
while ( a--, a < d ) ...
But in you case there is no reason to use it. It will be confusing... that's it...
In your case, it is just to avoid curly braces :
if(cond)
perror("an error occurred"), exit(1);
// =>
if (cond)
{
perror("an error occurred");
exit(1);
}
A link to a comma operator documentation.
There appear to be few practical uses of operator,().
Bjarne Stroustrup, The Design and Evolution of C++
Most of the oft usage of comma can be found out in the wikipedia article Comma_operator#Uses.
One interesting usage I have found out when using the boost::assign, where it had judiciously overloaded the operator to make it behave as a comma separated list of values which can be pushed to the end of a vector object
#include <boost/assign/std/vector.hpp> // for 'operator+=()'
using namespace std;
using namespace boost::assign; // bring 'operator+=()' into scope
{
vector<int> values;
values += 1,2,3,4,5,6,7,8,9; // insert values at the end of the container
}
Unfortunately, the above usage which was popular for prototyping would now look archaic once compilers start supporting Uniform Initialization
So that leaves us back to
There appear to be few practical uses of operator,().
Bjarne Stroustrup, The Design and Evolution of C++
In your case, the comma operator is useless since it could have been used to avoid curly braces, but it's not the case since the writer has already put them. Therefore it's useless and may be confusing.
It could be useful for the itinerary operator if you want to execute two or more instructions when the condition is true or false. but keep in mind that the return value will be the most right expression due to the comma operator left to right evalutaion rule (I mean inside the parentheses)
For instance:
a<b?(x=5,b=6,d=i):exit(1);
The boost::assign overloads the comma operator heavily to achieve this kind of syntax:
vector<int> v;
v += 1,2,3,4,5,6,7,8,9;
#include <stdio.h>
void main()
{
int x = 0;
if (x = 0)
printf("It's zero\n");
else
printf("It's not zero\n");
}
Why is the statement if (x = 0) not an error? Can we assign a value like that in an if statement? Why is it not generating an error, and why is the else statement getting executed?
Yes, it is allowed to assign the value inside the if statement. This is very handy, among other things, when you want to call the function and check it's return for error:
int rc;
if ((rc = check())) {
// here rc is non-zero, often an indication of a failure
}
Note how I've put an extra pair of parenthesis around my assignment - since it is such an omnipresent source of confusion, compilers are usually warning about assignement in the if block, assuming you might have made a typo. Extra pair of parenthesis makes it clear for compiler that this is what I intended.
By the way, there is no special exception crafted here, validity of this syntax stems from general C grammar - an assignment operator evaluates to assigned value.
Yes, this is a perfectly valid syntax, there is no reason to disallow this.
Quoting C11,
[...] An
assignment expression has the value of the left operand after the assignment. [...]
So, the value which is stored in the LHS operand, would be used for the if statement condition evaluation.
In your case, the variable x holds the value 0 after the assignment, and if (0) is FALSY, that's why the else block gets executed.
However, most of the time, this syntax is used wrongly, instead of the comparison. That's why most of the compilers emit a warning message on this construct.
warning: suggest parentheses around assignment used as truth value [-Wparentheses]
if (x = 0)
^
If you're sure what you're doing, you can wrap the if condition with an assignment expression in an additional pair of parenthesis, and you'll be good to go.
In C, the only requirement for an if statement is that it contains an expression. The truth of the statement is based on whether or not the expression evaluates to zero.
The assignment operator also evaluates to the assigned value, so if(a = 0) would be false, whereas if(a = x) where x != 0 would be true.
Since the assignment operator is an expression, it is acceptable to place in an if statement, though a frequent beginner mistake is to use the assignment operator where they intended to use the equality test operator ==.
One way you can avoid this is mistake is, if either side of the comparison is an r-value, put that on the left, so that if you ever accidentally use = where you meant ==, you will get a compilation error. Compare:
if(p = NULL) // Valid syntax
...
if(NULL = p) // Syntax error
...
The program I'm trying to write includes a macro to round a real number to the nearest integer and a function which uses that macro to round an array of real numbers.
Here's the program:
#include <stdio.h>
#define SIZE 256
#define round(N) { return (N >=0)? (int)(N+0.5) : (int)(N-0.5) ; }
void round_array(int a[])
{
int i;
for(i=0; i <SIZE; i++)
{
a[i] = round(a[i]);
}
}
int main()
{
return 0;
}
While compiling, I'm getting these errors:
round.c: In function ���round_array���:
round.c:4:18: error: expected expression before ���{��� token
#define round(N) { return (N >=0)? (int)(N+0.5) : (int)(N-0.5) ; }
^
round.c:11:15: note: in expansion of macro ���round���
a[i] = round(a[i]);
^
round.c: At top level:
Why am I getting these errors and how can I fix them?
Because after preprocessing, your code will look similar to that:
a[i] = { return (a[i] >=0)? (int)(a[i]+0.5) : (int)(a[i]-0.5) ; }
If you like to stick to macro, declare it as:
#define round(N) ((N) >=0)? (int)((N)+0.5) : (int)((N)-0.5)
But this is still not really correct because of int/float mixing. That is however already a different topic.
Like it was told to you in a comment, macros aren't functions. They are a token substitution mechanism. So you do not return from them as you would a function.
#define round(N) (((N) >=0)? (int)((N)+0.5) : (int)((N)-0.5))
The changes I made include:
Making it an expression. This involves replacing the curly braces with parentheses. This is so you could use the macro almost anywhere you could use a function. Had I left the curly braces it would have been a compound statement.
Wrapping the parameter N in parentheses as well, to make sure operator precedence doesn't come back and bite us.
Macro-replacement is basically what it sounds like, it replaces the macro with the body of the macro, quite literally.
So when you have
a[i] = round(a[i]);
It will be replaced by
a[i] = { return (a[i] >=0)? (int)(a[i]+0.5) : (int)(a[i]-0.5) ; };
That's not valid syntax. The right-hand side of an assignment must be an expression and not a statement.
A simple solution is to turn round from a macro to an actual function. An even simpler solution is to realize that int values (a[i] is an int) doesn't have fractions, so there's nothing to round.
If you want to use floating-point values though, the correct solution is to use the standard round function, not to make up your own.
If you insist on writing this yourself, you should replace the icky macro with a safer, cleaner function:
inline int int_round (double d)
{
return (int) ( d >= 0 ? d+0.5 : d-0.5 );
}
This should yield the very same machine code.
You don't need the return keyword, it's not a function. Get rid of it.
Quoting C11, chapter §6.8.6.4
A return statement terminates execution of the current function and returns control to
its caller. [...]
which is not the purpose of your MACRO definition. Inclusion of return keyword is unwanted and invalid syntax there.
What you probably want is a syntax like
(N >=0)? (int)(N+0.5) : (int)(N-0.5)
or, something better
( (N) >=0)? (int)((N)+0.5) : (int)((N)-0.5)
without the return and maybe the trailing ; also.
How can we interpret the following program and its success?(Its obvious that there must not be any error message). I mean how does compiler interpret lines 2 and 3 inside main?
#include <stdio.h>
int main()
{
int a,b;
a; //(2)
b; //(3)
return 0;
}
Your
a;
is just an expression statement. As always in C, the full expression in expression statement is evaluated and its result is immediately discarded.
For example, this
a = 2 + 3;
is an expression statement containing full expression a = 2 + 3. That expression evaluates to 5 and also has a side-effect of writing 5 into a. The result is evaluated and discarded.
Expression statement
a;
is treated in the same way, except that is has no side-effects. Since you forgot to initialize your variables, evaluation of the above expression can formally lead to undefined behavior.
Obviously, practical compilers will simply skip such expression statements entirely, since they have no observable behavior.
That's why you should use some compilation warning flags!
-Wall would trigger a "statement with no effect" warning.
If you want to see what the compilation produces, compile using -S.
Try it with your code, with/without -O (optimization) flag...
This is just like you try something like this:
#include <stdio.h>
int main(void){
1;
2;
return 0;
}
As we can see we have here two expressions followed by semicolon (1; and 2;). It is a well formed statement according to the rules of the language.
There is nothing wrong with it, it is just useless.
But if you try to use though statements (a or b) the behavior will be undefined.
Of course that, the compiler will interpret it as a statement with no effect
L.E:
If you run this:
#include <stdio.h>
int main(void){
int a;
int b;
printf("A = %d\n",a);
printf("B = %d\n",b);
if (a < b){
printf("TRUE");
}else{
printf("FALSE");
}
return 0;
}
You wil get:
A = 0
B = 0
FALSE
Because a and b are set to 0;
Sentences in C wich are not control structures (if, switch, for, while, do while) or control statements (break, continue, goto, return) are expressions.
Every expression has a resulting value.
An expression is evaluated for its side effects (change the value of an object, write a file, read volatile objects, and functions doing some of these things).
The final result of such an expression is always discarded.
For example, the function printf() returns an int value, that in general is not used. However this value is produced, and then discarded.
However the function printf() produces side effects, so it has to be processed.
If a sentence has no side effects, then the compiler is free to discard it at all.
I think that for a compiler will not be so hard to check if a sentence has not any side effects. So, what you can expect in this case is that the compiler will choose to do nothing.
Moreover, this will not affect the observable behaviour of the program, so there is no difference in what is obtained in the resulting execution of the program. However, of course, the program will run faster if any computation is ignored at all by the compiler.
Also, note that in some cases the floating point environment can set flags, which are considered side-effects.
The Standard C (C11) says, as part of paragraph 5.1.2.3p.4:
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 [...]
CONCLUSION: One has to read the documentation of the particular compiler that oneself is using.
What is the need for the conditional operator? Functionally it is redundant, since it implements an if-else construct. If the conditional operator is more efficient than the equivalent if-else assignment, why can't if-else be interpreted more efficiently by the compiler?
In C, the real utility of it is that it's an expression instead of a statement; that is, you can have it on the right-hand side (RHS) of a statement. So you can write certain things more concisely.
Some of the other answers given are great. But I am surprised that no one mentioned that it can be used to help enforce const correctness in a compact way.
Something like this:
const int n = (x != 0) ? 10 : 20;
so basically n is a const whose initial value is dependent on a condition statement. The easiest alternative is to make n not a const, this would allow an ordinary if to initialize it. But if you want it to be const, it cannot be done with an ordinary if. The best substitute you could make would be to use a helper function like this:
int f(int x) {
if(x != 0) { return 10; } else { return 20; }
}
const int n = f(x);
but the ternary if version is far more compact and arguably more readable.
The ternary operator is a syntactic and readability convenience, not a performance shortcut. People are split on the merits of it for conditionals of varying complexity, but for short conditions, it can be useful to have a one-line expression.
Moreover, since it's an expression, as Charlie Martin wrote, that means it can appear on the right-hand side of a statement in C. This is valuable for being concise.
It's crucial for code obfuscation, like this:
Look-> See?!
No
:(
Oh, well
);
Compactness and the ability to inline an if-then-else construct into an expression.
There are a lot of things in C that aren't technically needed because they can be more or less easily implemented in terms of other things. Here is an incomplete list:
while
for
functions
structs
Imagine what your code would look like without these and you may find your answer. The ternary operator is a form of "syntactic sugar" that if used with care and skill makes writing and understanding code easier.
Sometimes the ternary operator is the best way to get the job done. In particular when you want the result of the ternary to be an l-value.
This is not a good example, but I'm drawing a blank on somethign better. One thing is certian, it is not often when you really need to use the ternary, although I still use it quite a bit.
const char* appTitle = amDebugging ? "DEBUG App 1.0" : "App v 1.0";
One thing I would warn against though is stringing ternaries together. They become a real
problem at maintennance time:
int myVal = aIsTrue ? aVal : bIsTrue ? bVal : cIsTrue ? cVal : dVal;
EDIT: Here's a potentially better example. You can use the ternary operator to assign references & const values where you would otherwise need to write a function to handle it:
int getMyValue()
{
if( myCondition )
return 42;
else
return 314;
}
const int myValue = getMyValue();
...could become:
const int myValue = myCondition ? 42 : 314;
Which is better is a debatable question that I will choose not to debate.
Since no one has mentioned this yet, about the only way to get smart printf statements is to use the ternary operator:
printf("%d item%s", count, count > 1 ? "s\n" : "\n");
Caveat: There are some differences in operator precedence when you move from C to C++ and may be surprised by the subtle bug(s) that arise thereof.
The fact that the ternary operator is an expression, not a statement, allows it to be used in macro expansions for function-like macros that are used as part of an expression. Const may not have been part of original C, but the macro pre-processor goes way back.
One place where I've seen it used is in an array package that used macros for bound-checked array accesses. The syntax for a checked reference was something like aref(arrayname, type, index), where arrayname was actually a pointer to a struct that included the array bounds and an unsigned char array for the data, type was the actual type of the data, and index was the index. The expansion of this was quite hairy (and I'm not going to do it from memory), but it used some ternary operators to do the bound checking.
You can't do this as a function call in C because of the need for polymorphism of the returned object. So a macro was needed to do the type casting in the expression.
In C++ you could do this as a templated overloaded function call (probably for operator[]), but C doesn't have such features.
Edit: Here's the example I was talking about, from the Berkeley CAD array package (glu 1.4 edition). The documentation of the array_fetch usage is:
type
array_fetch(type, array, position)
typeof type;
array_t *array;
int position;
Fetch an element from an array. A
runtime error occurs on an attempt to
reference outside the bounds of the
array. There is no type-checking
that the value at the given position
is actually of the type used when
dereferencing the array.
and here is the macro defintion of array_fetch (note the use of the ternary operator and the comma sequencing operator to execute all the subexpressions with the right values in the right order as part of a single expression):
#define array_fetch(type, a, i) \
(array_global_index = (i), \
(array_global_index >= (a)->num) ? array_abort((a),1) : 0,\
*((type *) ((a)->space + array_global_index * (a)->obj_size)))
The expansion for array_insert ( which grows the array if necessary, like a C++ vector) is even hairier, involving multiple nested ternary operators.
It's syntatic sugar and a handy shorthand for brief if/else blocks that only contain one statement. Functionally, both constructs should perform identically.
like dwn said, Performance was one of its benefits during the rise of complex processors, MSDN blog Non-classical processor behavior: How doing something can be faster than not doing it gives an example which clearly says the difference between ternary (conditional) operator and if/else statement.
give the following code:
#include <windows.h>
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
int array[10000];
int countthem(int boundary)
{
int count = 0;
for (int i = 0; i < 10000; i++) {
if (array[i] < boundary) count++;
}
return count;
}
int __cdecl wmain(int, wchar_t **)
{
for (int i = 0; i < 10000; i++) array[i] = rand() % 10;
for (int boundary = 0; boundary <= 10; boundary++) {
LARGE_INTEGER liStart, liEnd;
QueryPerformanceCounter(&liStart);
int count = 0;
for (int iterations = 0; iterations < 100; iterations++) {
count += countthem(boundary);
}
QueryPerformanceCounter(&liEnd);
printf("count=%7d, time = %I64d\n",
count, liEnd.QuadPart - liStart.QuadPart);
}
return 0;
}
the cost for different boundary are much different and wierd (see the original material). while if change:
if (array[i] < boundary) count++;
to
count += (array[i] < boundary) ? 1 : 0;
The execution time is now independent of the boundary value, since:
the optimizer was able to remove the branch from the ternary expression.
but on my desktop intel i5 cpu/windows 10/vs2015, my test result is quite different with msdn blog.
when using debug mode, if/else cost:
count= 0, time = 6434
count= 100000, time = 7652
count= 200800, time = 10124
count= 300200, time = 12820
count= 403100, time = 15566
count= 497400, time = 16911
count= 602900, time = 15999
count= 700700, time = 12997
count= 797500, time = 11465
count= 902500, time = 7619
count=1000000, time = 6429
and ternary operator cost:
count= 0, time = 7045
count= 100000, time = 10194
count= 200800, time = 12080
count= 300200, time = 15007
count= 403100, time = 18519
count= 497400, time = 20957
count= 602900, time = 17851
count= 700700, time = 14593
count= 797500, time = 12390
count= 902500, time = 9283
count=1000000, time = 7020
when using release mode, if/else cost:
count= 0, time = 7
count= 100000, time = 9
count= 200800, time = 9
count= 300200, time = 9
count= 403100, time = 9
count= 497400, time = 8
count= 602900, time = 7
count= 700700, time = 7
count= 797500, time = 10
count= 902500, time = 7
count=1000000, time = 7
and ternary operator cost:
count= 0, time = 16
count= 100000, time = 17
count= 200800, time = 18
count= 300200, time = 16
count= 403100, time = 22
count= 497400, time = 16
count= 602900, time = 16
count= 700700, time = 15
count= 797500, time = 15
count= 902500, time = 16
count=1000000, time = 16
the ternary operator is slower than if/else statement on my machine!
so according to different compiler optimization techniques, ternal operator and if/else may behaves much different.
Some of the more obscure operators in C exist solely because they allow implementation of various function-like macros as a single expression that returns a result. I would say that this is the main purpose why the ?: and , operators are allowed to exist, even though their functionality is otherwise redundant.
Lets say we wish to implement a function-like macro that returns the largest of two parameters. It would then be called as for example:
int x = LARGEST(1,2);
The only way to implement this as a function-like macro would be
#define LARGEST(x,y) ((x) > (y) ? (x) : (y))
It wouldn't be possible with an if ... else statement, since it does not return a result value. Note)
The other purpose of ?: is that it in some cases actually increases readability. Most often if...else is more readable, but not always. Take for example long, repetitive switch statements:
switch(something)
{
case A:
if(x == A)
{
array[i] = x;
}
else
{
array[i] = y;
}
break;
case B:
if(x == B)
{
array[i] = x;
}
else
{
array[i] = y;
}
break;
...
}
This can be replaced with the far more readable
switch(something)
{
case A: array[i] = (x == A) ? x : y; break;
case B: array[i] = (x == B) ? x : y; break;
...
}
Please note that ?: does never result in faster code than if-else. That's some strange myth created by confused beginners. In case of optimized code, ?: gives identical performance as if-else in the vast majority of the cases.
If anything, ?: can be slower than if-else, because it comes with mandatory implicit type promotions, even of the operand which is not going to be used. But ?: can never be faster than if-else.
Note) Now of course someone will argue and wonder why not use a function. Indeed if you can use a function, it is always preferable over a function-like macro. But sometimes you can't use functions. Suppose for example that x in the example above is declared at file scope. The initializer must then be a constant expression, so it cannot contain a function call. Other practical examples of where you have to use function-like macros involve type safe programming with _Generic or "X macros".
ternary = simple form of if-else. It is available mostly for readability.
The same as
if(0)
do();
if(0)
{
do();
}