Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are string literals l-value while all other literals are r-value?

C++03 5.1 Primary expressions §2 says:

A literal is a primary expression. Its type depends on its form (2.13). A string literal is an lvalue; all other literals are rvalues.

Similarly, C99 6.5.1 §4 says:

A string literal is a primary expression. It is an lvalue with type as detailed in 6.4.5.

What is the rationale behind this?

As I understand, string literals are objects, while all other literals are not. And an l-value always refers to an object.

But the question then is why are string literals objects while all other literals are not? This rationale seems to me more like an egg or chicken problem.

I understand the answer to this may be related to hardware architecture rather than C/C++ as programming languages, nevertheless I would like to hear the same.

like image 762
Alok Save Avatar asked Apr 04 '12 03:04

Alok Save


People also ask

Is a string literal an rvalue or lvalue?

Its type depends on its form (2.13). A string literal is an lvalue; all other literals are rvalues.

What is the relationship between lvalue and rvalue?

An lvalue (locator value) represents an object that occupies some identifiable location in memory (i.e. has an address). rvalues are defined by exclusion. Every expression is either an lvalue or an rvalue, so, an rvalue is an expression that does not represent an object occupying some identifiable location in memory.

What is special about a string literal?

A "string literal" is a sequence of characters from the source character set enclosed in double quotation marks (" "). String literals are used to represent a sequence of characters which, taken together, form a null-terminated string. You must always prefix wide-string literals with the letter L.

What is the difference between string literal and character literal?

What is the difference between character literals and string literals in Java? Character literals represents alphabets (both cases), numbers (0 to 9), special characters (@, ?, & etc.) and escape sequences like \n, \b etc. Whereas, the String literal represents objects of String class.


2 Answers

A string literal is a literal with array type, and in C there is no way for an array type to exist in an expression except as an lvalue. String literals could have been specified to have pointer type (rather than array type that usually decays to a pointer) pointing to the string "contents", but this would make them rather less useful; in particular, the sizeof operator could not be applied to them.

Note that C99 introduced compound literals, which are also lvalues, so having a literal be an lvalue is no longer a special exception; it's closer to being the norm.

like image 174
R.. GitHub STOP HELPING ICE Avatar answered Oct 12 '22 13:10

R.. GitHub STOP HELPING ICE


String literals are arrays - objects of inherently unpredictable size (i.e of user-defined and possibly large size). In general case, there's simply no other way to represent such literals except as objects in memory, i.e. as lvalues. In C99 this also applies to compound literals, which are also lvalues.

Any attempts to artificially hide the fact that string literals are lvalues at the language level would produce a considerable number of completely unnecessary difficulties, since the ability to point to a string literal with a pointer as well as the ability to access it as an array relies critically on its lvalue-ness being visible at the language level.

Meanwhile, literals of scalar types have fixed compile-time size. At the same time, such literals are very likely to be embedded directly into the machine commands on the given hardware architecture. For example, when you write something like i = i * 5 + 2, the literal values 5 and 2 become explicit (or even implicit) parts of the generated machine code. They don't exist and don't need to exist as standalone locations in data storage. There's simply no point in storing values 5 and 2 in the data memory.

It is also worth noting that on many (if not most, or all) hardware architectures floating-point literals are actually implemented as "hidden" lvalues (even though the language does not expose them as such). On platforms like x86 machine commands from floating-point group do not support embedded immediate operands. This means that virtually every floating-point literal has to be stored in (and read from) data memory by the compiler. E.g. when you write something like i = i * 5.5 + 2.1 it is translated into something like

const double unnamed_double_5_5 = 5.5; const double unnamed_double_2_1 = 2.1; i = i * unnamed_double_5_5 + unnamed_double_2_1; 

In other words, floating-point literals often end up becoming "unofficial" lvalues internally. However, it makes perfect sense that language specification did not make any attempts to expose this implementation detail. At language level, arithmetic literals make more sense as rvalues.

like image 44
AnT Avatar answered Oct 12 '22 14:10

AnT