Why does this compile.

Hi,

When I run this sketch (arduino 1.6.5)

void setup() {
  // put your setup code here, to run once:
Serial.print("avg of =<"); Serial.print(">. was <");("> Took <"); Serial.println(">ms");
}

void loop() {
  // put your main code here, to run repeatedly:

}

It compiles and uploads fine

Sketch uses 1,838 bytes (0%) of program storage space. Maximum is 253,952 bytes.
Global variables use 222 bytes (2%) of dynamic memory, leaving 7,970 bytes for local variables. Maximum is 8,192 bytes.

But it shouldn’t (I’ve missed the Serial.print before one the strings)

It’s only if this line is included in a sketch that actually does something that it screws up the functionality of that sketch.

So why does it compile without warnings?

The syntax is all correct, so it compiles. That you have your logic flow incorrect (missing Serial.begin(speed) ) is not the compiler's fault.

That you have your logic flow incorrect (missing Serial.begin(speed) ) is not the compiler’s fault.

Well done, you spotted the non-deliberate error.

However I also included this…

("> Took <");

Which Should be…

Serial.print("> Took <");

My understanding (which I’ll admit frequently lets me down) is that

("> Took <");

Is an invalid statement and I would expect it to generate errors?

Nope, it is simply an expression that evaluates to a constant string that is thrown away.

Actually, if you load your statement into a shell program:

void setup() {

  ("> Took <");
}

void loop() {

}

it will compile just fine because it contains all that’s necessary to construct a statement. Other than logic errors, you can have syntax and semantic errors in a program. For example, the rules of English say a sentence must have a noun and a verb. So the sentence:

The dog meowed.

follows the syntax rules, but the operands of the sentence don’t make sense…a semantic error. Because your statement does obey the syntax rules, it compiles. The semantic error, however, prevents it from doing anything useful.

Ok guys, thanks for your help.

Same as this compiling, but not doing what is intended (in almost all cases):

if (a=b){ // do something } which doesn't compare if a is equal to b (which needs a==b), but merely sets a to the value of b, which is apparently then evaluated as a true statement, and "do something" is done every time. Bad logic, but valid syntax.

No, crossroads. If B is 0 it will be seen as false and fail the test.

A correct idiom for this is

if (a = operationThatReturnsZeroOnFailure()) {}

where you do want to save the value of a for later use, but check for a failure. This is why you cannot just test for == or = in an if, there are valid uses of = in a conditional.

Well, I had it mostly correct 8) I make sure to use == in my basic style coding.

CrossRoads: Same as this compiling, but not doing what is intended (in almost all cases):

if (a=b){ // do something } which doesn't compare if a is equal to b (which needs a==b), but merely sets a to the value of b, which is apparently then evaluated as a true statement, and "do something" is done every time. Bad logic, but valid syntax.

To set you straight, the declaration of the assignment operator usually goes like this:

type& operator =(type& lhs, const type& rhs);

It assigns the value of rhs to lhs, and returns a mutable (ie. not const) reference to lhs. This means that this bit of silliness is also perfectly legal:

int a = 2;
 int b = 5;

 (a=b) += 5;

Printing out a and b at the end shows that a is now 10 and b is still 5.

As KeithRB says, there are occasions where this is desired behavior. They're just rare.

Are you sure about that? (a=b) returns b, not &a.

I would expect a=b=c to work, but not (a=b) = c.

Just to add, yes it does work. I was wrong. Strangely enough &(a+b) works, too.

I am confused.

KeithRB: Are you sure about that? (a=b) returns b, not &a.

I would expect a=b=c to work, but not (a=b) = c.

it looks like it returns b, because it returns the reference to a after the assignment has been done. It may seem a small detail, but if you overload the assignment operator such that a and b don't compare equal after an assignment (which is possible, just bizarre that someone would do that), you will notice the difference.

Why would you expect one of those statements to work (I assume you mean compile) and not the other? Both are legal C++ statements, but do different things because assignment is not commutative and has right-to-left associativity.

In the first one, a and b will be assigned the value of c, and c will be unchanged. In the second, a will be assigned the value of c, and b and c will be unchanged.

Just to add, yes it does work. I was wrong. Strangely enough &(a+b) works, too.

I am confused.

So am I. When I compile a program with that statement in it I get:

140 7   C:\Google Drive\Documents\C++ Programs\Test\main.cpp    [Error] lvalue required as unary '&' operand

Which compiler? I used the arduino IDE.

I guess I am confused because in your example: (a=b) += 5;

It looks like (a=b) must be yielding the lvalue for b, but in the if statement it returns b.

KeithRB:
Which compiler? I used the arduino IDE.

I guess I am confused because in your example:
(a=b) += 5;

It looks like (a=b) must be yielding the lvalue for b, but in the if statement it returns b.

A desktop x86 compiler at first (TDM-GCC 4.9.2 64-bit), but doing it with arduino 1.6.9 shows the same error message.

void setup()
{

  int a=3;
  int b=5;

  &(a+b);
}
void loop(){}

Addition operators tend to return by value, not reference, and you cannot use the address-of operator on a temporary value.

I just looked at the keyboard though, did you SHIFT it accidentally? Changing the + to = compiles, but it throws a warning about “right operand of comma operator has no effect”, which is weird because there are no comma operators.

Regarding the original statement, this is what I ran with the desktop C++ compiler:

#include <iostream>
#include <iomanip>

using namespace std;

int main(int argc, char* argv[])
{
 int a = 2;
 int b = 5;
 
 (a=b) += 5;
 
 cout << a << endl << b << endl;
 return 0;
}

And this is what shows on stdout:

C:\Google Drive\Documents\C++ Programs\Test>"Test"
10
5

The assignment operator returns a reference to a, then operator+=(5) is applied to that, added 5 to the value of a and assigning the value into a. b is not modified.

I’ll put this to bed right here. I said you could tell the difference by overloading assignment, so let’s do exactly that:

#include <iostream>
#include <iomanip>

struct bizarre_int
{
public:
	bizarre_int(int i) : _v(i) {}
	
	bizarre_int& operator=(const bizarre_int& rhs) {_v=5;}
	
	operator int() {return _v;}
private:
	int _v;
};

int main(int argc, char** argv) {
	bizarre_int alpha(10), bravo(10);
	std::cout << (int)(alpha = bravo);
	
	return 0;
}

This is not Arduino code, but it follows the same rules. Here I have created the bizarre_int struct. The bizarre part is that the assignment operator has been overloaded so that whenever a bizarre_int is assigned to another bizarre_int, the value 5 is assigned, completely ignoring the value of the rhs operand. This defies all rules of logic as well as the very meaning of the word assignment, but it is legal code.

rhs is declared a const reference in the operator= overload, so bravo cannot be modified by the assignment operation. They both start with a value of 10, but the assignment changes alpha to 5 and bravo is unmodified. What do you suppose is printed to cout when running this program?

C:\Google Drive\Documents\C++ Programs\Dumb One>test2
5

Unambiguously, alpha is printed, not any part of bravo.

I just realized on the drive home that the overloading example is not quite as persuasive as I thought, since I can overload it to do whatever I want, including returning a reference to the rhs operand instead of lhs.

#include <iostream>
#include <iomanip>

struct bizarre_int
{
public:
	bizarre_int(int i) : _v(i) {}
	
	bizarre_int& operator=(bizarre_int& rhs) {_v=5; return rhs;}
	
	operator int() {return _v;}
private:
	int _v;
};

int main(int argc, char** argv) {
	bizarre_int alpha(10), bravo(10);
	std::cout << (int)(alpha = bravo) << "\n";
	std::cout << (int)alpha << "\n";
	std::cout << (int)bravo << "\n";
	
	return 0;
}

stdout:

C:\Users\MDowd\Documents\1) Flash Drive Documents\C++ Programs\Simple Tests>Test2
10
5
10

alpha was modified by the assignment, but a reference to bravo was returned.

The (a+b)+=5 example I posted above using primitive types still shows conclusively that the normal behavior of the assignment operator is to return a mutable reference to the left-hand side operand.