Historisch gezien is het onderscheid tussen lvalue en rvalue in de C-taal ontstaan als basis voor het bepalen welke expressies de toewijzingsoperator kunnen gebruiken. Lvalue (left value) verwijst naar een object dat een bepaalde plaats in het geheugen bezet en waaraan de operator om het adres te nemen (&) kan worden toegepast. Rvalue (right value) is een tijdelijke waarde zonder een bepaald adres. Dit onderscheid is belangrijk voor het begrijpen van hoe toewijzing, argumentoverdracht naar functies en optimalisatie door de compiler werkt.
Het probleem ontstaat wanneer je probeert bewerkingen uit te voeren die alleen op lvalue zijn toegestaan (bijvoorbeeld toewijzing) voor rvalue, en vice versa. Dit kan leiden tot compilatiefouten of onduidelijke bugs tijdens de uitvoering.
De oplossing ligt in een duidelijk begrip van de contexten waarin lvalue en rvalue worden gebruikt. Voorbeeld:
int x = 5; int y; y = x; // x is zowel lvalue als rvalue, y is lvalue y = x + 1; // x + 1 is rvalue (adres kan niet worden genomen) // &x is correct, &(x + 1) is een fout
Belangrijke kenmerken:
Kan je het adres van elke expressie nemen, bijvoorbeeld van de expressie (x + y)?
Nee, alleen lvalue heeft een adres. Bijvoorbeeld, de expressie (x + y) is rvalue.
int z = 3, y = 7; int *p = &(z + y); // Compilatiefout
Wat gebeurt er als je probeert een waarde aan een constante toe te wijzen (bijvoorbeeld 5 = x)?
Er zal een compilatiefout optreden, omdat de letterlijke waarde 5 een rvalue is en niet als lvalue kan fungeren.
5 = x; // Fout: de linkeroperand is geen lvalue
Kan een functie lvalue retourneren?
Een gewone functie retourneert rvalue, maar als een referentie wordt geretourneerd (bijvoorbeeld in C++), dan is dit lvalue. In C zijn alleen retouren van rvalue toegestaan.
int foo() { int x = 5; return x; } // Rvalue wordt geretourneerd
Een programmeur probeerde het adres van een tijdelijke resultaat van de expressie (a + b) te nemen:
int *p = &(a + b);
Voordelen:
Nadelen:
Een programmeur maakt bewust een scheiding tussen lvalue en rvalue. Hij gebruikt waarden alleen waar de syntaxis en semantiek dit toestaan:
int x = 7; int *p = &x; // correct
Voordelen:
Nadelen: