Fixing "lvalue required as left operand of assignment" in Arduino
Beginner
Or see every lesson.
- 455parts on the bench
- 43boards running now
- 1.00xreal time, on every board
lvalue required as left operand of assignment means the left side of an = is something that cannot be changed. An lvalue is a thing with a place in memory, a variable, that can be given a new value; digitalRead(2), LOW, x + 1 and 13 are values, not places. Nine times in ten the line is a comparison written with one = where it needs two: if (digitalRead(2) = LOW).
Mokxi compiles with clang, which says expression is not assignable for the same line. The circuit above lights the LED on pin 13 while the button on pin 2 is held. Open it, change the == in digitalRead(BUTTON_PIN) == LOW to = and press Run: the build stops with expression is not assignable, and the build tab says "The left side of = has to be a variable that can change. To compare two values, use == instead."
= where == belongs
One = sets a variable; two compare. In if (digitalRead(2) = LOW) the compiler reads an instruction to store LOW into digitalRead(2), which is a value the function hands back, not a place. GCC says lvalue required as left operand of assignment and clang says expression is not assignable, both at the =. Write ==.
Writing the constant first, if (LOW = state), gives the same error, which is why some people write comparisons that way around on purpose: LOW is the number 0 (#define LOW 0x0 in the Arduino core’s Arduino.h), so one = can never build. The usual way around, if (state = LOW), builds without a complaint in the Arduino IDE, and that is the worse bug of the two.
The one that builds: if (state = LOW)
With the variable on the left, state = LOW is a legal assignment. It sets state to 0, and the if then tests that 0, so the condition is false every time, whatever the button does. We ran the sketch below with the button held down for the whole run, and it printed "not pressed" four times out of four.
Clang builds it with a warning: using the result of an assignment as a condition without parentheses, and Mokxi’s build tab says "A single = sets the variable to the value, it does not compare them, so this condition is true whenever that value is not 0. To compare, use two: if (v == HIGH)." GCC warns too, suggest parentheses around assignment used as truth value, but only with warnings turned on, and the Arduino IDE has them off unless you change Compiler warnings in its preferences. With == the same sketch printed "pressed" four times while the button was held.
void setup() {
Serial.begin(9600);
pinMode(2, INPUT_PULLUP);
}
void loop() {
int state = digitalRead(2);
if (state = LOW) {
Serial.println("pressed");
} else {
Serial.println("not pressed");
}
delay(500);
}&& and = on one line
if (x > 5 && y = 3) looks like two tests joined by &&, but && binds more tightly than =, so the compiler reads (x > 5 && y) = 3: an assignment to the result of &&, which is a value. GCC said lvalue required as left operand of assignment; clang said expression is not assignable. The = was meant as ==, and with it the line builds. if (x + 1 = 5) fails the same way, because x + 1 is a value, not a variable.
A function call or a #define on the left
millis() = 0; is a common try at resetting the clock. It gave GCC’s lvalue required and clang’s not assignable: millis() hands back a number and keeps counting. Keep your own start time instead, unsigned long start = millis();, and measure from it with millis() - start.
A pin name made with #define LED 13 cannot be changed later either. LED = 12; becomes 13 = 12; before the compiler sees it, so GCC said lvalue required and clang expression is not assignable. If the pin really has to change while the sketch runs, make it a variable: int led = 13;.
A const or an array: the same mistake in other words
Change a const and the message names it. With const int LED = 13;, the line LED = 12; gave GCC’s assignment of read-only variable 'LED' and clang’s cannot assign to variable 'LED' with const-qualified type 'const int', with a note pointing at the declaration: variable 'LED' declared const here. Drop the const if the value has to change.
A char array cannot be given new text with = after it is declared. name = "Bob"; with char name[10]; gave clang’s array type 'char[10]' is not assignable, and GCC’s incompatible types in assignment of 'const char [4]' to 'char [10]'. Copy the text in with strcpy(), as below, which printed "Bob", or use a String, which can be assigned.
char name[10];
void setup() {
Serial.begin(9600);
strcpy(name, "Bob");
Serial.println(name);
}
void loop() {
}The other way around: == where = belongs
count == 5; on a line of its own compares count with 5 and throws the answer away, so count stays 0. It builds. Clang warned equality comparison result unused, with the note use '=' to turn this equality comparison into an assignment, and the sketch printed 0. GCC, with warnings on, says statement has no effect.
Questions
What does "lvalue required as left operand of assignment" mean?
The left side of = is not a variable, so nothing can be stored there: a function call, a number, a #define or a sum. Usually the = was meant to be ==, a comparison.
What is an lvalue?
Something with a place in memory that can be given a value, such as a variable or an element of an array. It is called that because it can stand on the left of =.
Why does if (x = 5) compile but always run?
x = 5 is a legal assignment, and its result, 5, counts as true, so the if runs every time; x = 0 would make it never run. Use == to compare. Clang warns about it, and GCC does with warnings turned on.
What does clang say instead?
Mokxi’s compiler, clang, says expression is not assignable. For a const it says cannot assign to variable with const-qualified type, and for an array, array type is not assignable.
Keep going
Where the facts on this page come from
Build this for real
Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.