I have three code snippets. This one:
1,7; //yes, that's all the code
compiles okay. This one:
double d = (1, 7);
also compiles okay. Yet this one:
double d = 1, 7;
fails to compile. gcc-4.3.4 says
error: expected unqualified-id before numeric constant
and Visual C++ 10 says
error C2059: syntax error : 'constant'
Why such difference? Why don't all the three compile with , having the same effect in all three?
In the first two cases, the statements are using C++'s comma operator
In the latter case, comma is being used as variable separate and the compiler is expecting you to declare multiple identifiers; the comma is not being used as the operator here.
The last case is similar to something like:
float x,y;
float a = 10, b = 20;
When you do this:
double d = 1, 7;
The compiler expects a variable identifier and not a numeric constant. Hence 7 is illegal here.
However when you do this:
double d = (1,7);
the normal comma operator is being used: 1 gets evaluated and discard while 7 is stored in d.
The difference is that in 1, 7; and (1, 7) you have expressions where a comma operator is allowed.
Your last example
double d = 1, 7;
is a declaration, where the comma isn't an operator but a separator. The compiler exepcts something like
double d = 1, e = 7;
which would be a correct variable declaration.
Note that the comma is sometimes an operator (in expressions), but is also used as a separator in other places like parameter lists in function declarations.
double d = (1, 7); Here the (1, 7) will be evaluated
first; the comma works as sequential-evaluation operator, and
7 will be assigned to d.
double d = 1, 7; In this case there is a problem: the part
before the comma means you declare a double and set its value, but
the part after the comma is meaningless, because it's just a single
integer constant.
I believe it is because the last one is treated as (incorrect) declaration line: (double d = 1), (7)
Related
Why does an expression i = 2 return 2? What is the rule this is based on?
printf("%d\n", i = 2 ); /* prints 2 */
I am in C domain after spending long time in Java/C#. Forgive my ignorance.
It evaluates to 2 because that's how the standard defines it. From C11 Standard, section 6.5.16:
An assignment expression has the value of the left operand after the assignment
It's to allow things like this:
a = b = c;
(although there's some debate as to whether code like that is a good thing or not.)
Incidentally, this behaviour is replicated in Java (and I would bet that it's the same in C# too).
The rule is to return the right-hand operand of = converted to the type of the variable which is assigned to.
int a;
float b;
a = b = 4.5; // 4.5 is a double, it gets converted to float and stored into b
// this returns a float which is converted to an int and stored in a
// the whole expression returns an int
It consider the expression firstly then print the leftmost variable.
example:
int x,y=10,z=5;
printf("%d\n", x=y+z ); // firstly it calculates value of (y+z) secondly puts it in x thirdly prints x
Note:
x++ is postfix and ++x is prefix so:
int x=4 , y=8 ;
printf("%d\n", x++ ); // prints 4
printf("%d\n", x ); // prints 5
printf("%d\n", ++y ); // prints 9
Assign the value 2 to i
Evaluate the i variable and display it
In C (almost) all expressions have 2 things
1) a value
2) a side effect
The value of the expression
2
is 2; its side effect is "none";
The value of the expression
i = 2
is 2; its side effect is "changing the value in the object named i to 2";
I have recently noticed an strange valid C/C++ expression in GCC/Clang which I have never seen before. Here is the example in C++, but similar expression works in C too:
int main(){
int z = 5;
auto x = ({z > 3 ? 3 : 2;}); // <-- expression
std::cout << x;
}
What it does is somehow obvious, but I like to know what it is called. Since it does not worth in MSVC, I guess it is a non-standard extension. But is there anything that works for MSVC too? especially in C?
It's called statement expr, used in GCC. Your expression ({z > 3 ? 3 : 2;}) can be translated to
if (z > 3) {x = 3;} else {x = 2;}
From documentation:
A compound statement enclosed in parentheses may appear as an
expression in GNU C. This allows you to use loops, switches, and local
variables within an expression.
In other word, it provides the ability to put a compound statement in an expression position.
Related post :
Emulating GCC Statement Expressions
Use of ({ ... }) brackets in macros to swallow the semicolon
It is called conditional operator . Return will be depend on condition either condition is true or false.
But in this case:
auto x = ({z > 3 ? 3 : 2;}); // <-- expression
if Z is greater than 3 returns 3 otherwise 2.
Basic syntax : Expression1? expression2: expression3;
Consider the following snippets:
C++:
#include <iostream>
using namespace std;
int main()
{
int x = 10, y = 20;
y = x + (x=y)*0;
cout << y;
return 0;
}
which gives a result of 20, because the value of y is assigned to x since the bracket is executed first according to the Operator Precedence Table.
VB.NET:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim x As Integer = 10
Dim y As Integer = 20
y = x + (x = y) * 0
MsgBox(y)
End Sub
which instead gives a result of 10.
What is the reason for this difference?
What is the order of execution of operators in VB.NET?
Unlike in C++, VB.NET's = is not always an assignment. It can also be the equality comparison operator (== in C++) if it appears inside an expression. Therefore your two expressions are not the same. They are not even equivalent. The VB.NET code does not do what you might think it does.
First to your C++ code: Like you're saying, the assignment x=y happens first; thus your code is roughly equivalent to this: (It seems that was incorrect; see Jens' answer.) Since you end up with y being 20, it is likely that your C++ compiler evaluated your code as if you had written this:
int x = 10, y = 20;
x = y;
y = x + x*0; // which is equivalent to `y = 20 + 20*0;`, or `y = 20 + 0;`, or `y = 20;`
In VB.NET however, because the = in your subexpression (x=y) is not actually interpreted as an assignment, but as a comparison, the code is equivalent to this:
Dim x As Integer = 10
Dim y As Integer = 20
y = 10 + False*0 ' which is equivalent to `y = 10 + 0*0`, or `y = 10` '
Here, operator precedence doesn't even come into play, but an implicit type conversion of the boolean value False to numeric 0.
(Just in case you were wondering: In VB.NET, assignment inside an expression is impossible. Assignments must always be full statements of their own, they cannot happen "inline". Otherwise it would be impossible to tell whether a = inside an expression meant assignment or comparison, since the same operator is used for both.)
Your C++ snippet is undefined behavior. There is no sequence point between using x as the first argument and assigning y to x, so the compiler can evaluate the sub-expressions in any order. Both
First evaluate the left side: y = 10 + (x=y) * 0 -> y = 10 + (x=20) * 0 -> y = 10 + 20*0
First evaluate the right side: y = x + (x=20) * 0 -> y = 20 + 20 * 0
It is also generally a very bad style to put assignments inside expressions.
This answer was intended as a comment, but its length quickly exceeded the limit. Sorry :)
You are confusing operator precedence with evaluation order. (This is a very common phenomenon, so don't feel bad). Let me try to explain with a simpler example involving more familiar operators:
If you have an expression like a + b * c then yes, the multiplication will always happen before the addition, because the * operator binds tighter than + operator. So far so good? The important point is that C++ is allowed to evaluate the operands a, b and c in any order it pleases. If one of those operands has a side effect which affects another operand, this is bad for two reasons:
It may cause undefined behavior (which in your code is indeed the case), and more importantly
It is guaranteed to give future readers of your code serious headaches. So please don't do it!
By the way, Java will always evaluate a first, then b, then c, "despite" the fact that multiplication happens before addition. The pseudo-bytecode will look like push a; push b; push c; mul; add;
(You did not ask about Java, but I wanted to mention Java to give an example where evaluating a is not only feasible, but guaranteed by the language specification. C# behaves the same way here.)
I've been debugging some SSE-optimised vector code and noticed some odd behaviour. To be fair, the code style is pretty bad, but what the compiler does still seems wrong to me. Here is the function in question:
inline void daxpy(int n, double alph, const double* x, int incx, double* y, int incy) {
__m128d sse_alph = _mm_load1_pd(&alph);
while (n >= 4) {
n -= 4;
__m128d y1 = _mm_load_pd(y+n), y2 = _mm_load_pd(y+n+2);
__m128d x1 = _mm_load_pd(x+n), x2 = _mm_load_pd(x+n+2);
y1 = _mm_add_pd(y1, _mm_mul_pd(x1, sse_alph));
y2 = _mm_add_pd(y2, _mm_mul_pd(x2, sse_alph));
_mm_store_pd(y+n, y1), _mm_store_pd(y+n+2, y2);
}
}
The function is that the array y = y + alph * x. We guarantee that the arrays both have the same length, n, which is a multiple of 4, and that x and y are aligned on 16-byte boundaries (I've omitted the relevant assertions for clarity).
The last line of the loop has been written with a comma operator so that it looks like the two load lines. The problem is that the first _mm_store_pd call is not executed. Isn't that wrong? I guess the compiler might have decided that only the second call is necessary to evaluate the expression, but it seems pretty obvious that the intrinsic function has a side effect.
Have I misunderstood what is going on here? I realise that using a comma operator like this is pretty poor style - my question is whether the compiler is wrong. The compiler in question is Visual C++ 2010 SP 1.
Building this code with Microsoft Visual Studio 2008, 2010, and 2012 shows they all eliminate the left operand of the comma operator. This happens only if optimization is enabled. When this code is built using gcc 4.8.1, the left operand of the comma operator is not eliminated, even when full optimization is used.
The C99 specification states, "The left operand of a comma operator is evaluated as a void expression; there is a sequence point after its evaluation. Then the right operand is evaluated".
In my opinion, the Microsoft optimizer is incorrect to remove this code. This is because the language specification says both operands are evaluated. The only differences between the two operands of the comma operator are the order of their evaluation and which one provides the result for the comma operator. In this case the result is void.
Work-around: replace the comma with a semicolon.
I am a total FORTRAN 77 newbie, and I don't understand why the first code shows an error while the second one compiles when I expect them to do the same.
First code (which doesn't compile and gives a error citing an unexpected data declaration statement at z):
program FOO
integer x, y
x = 1
y = 2
integer z
z = 3
end
This code which looks 100% similar in functionality to the first one compiles without errors
program FOO
integer x, y, z
x = 1
y = 2
z = 3
end
I also tried disabling implicit variable declarations in the first code with no effects.
Fortran is one of those quaint "define everything at the top" languages. In other words, this would be fine:
program FOO
integer x, y
integer z
x = 1
y = 2
z = 3
end
since all type specifications are before any executable code. If you're going to define a variable, you should define it first. See here for example:
Such non-executable statements must be placed at the beginning of a program, before the first executable statement.
I don't know real solution but maybe fortran77 doesn't support any code between variables.
for example;
integer x, y, z
x = 1
y = 2
z = 3
works but
integer x, y
x = 1
y = 2
integer z
z = 3
doesn't work. Because between two integer definening (integer x, y and integer z ), there are variables assigning.
#paxdiablo: you think right!
and the errormessage:
"... unexpected data declaration statement at ..."
all DELCARATION must be made BEFORE the first STATEMENT occurs. fortran77 is really "old", I´m not shure if this is changed in F95
For your information: Disabling implicit variable declarations simply removes Fortan's ability to make assumptions about what type your variables are.
Implicit variable declaration makes the following assumptions: Any variable beginning with (capital or lowercase): I, J, K, L, M, or N is to be INTEGER. Any variable beginning with any other letter (capital or lowercase) is to be REAL. This applies only to variables which do not have an explicit type declaration.
You could write:
program FOO
ijk
ifjkask
end
and ijk and ifjkask would be INTEGER values.