lvalues and rvalues

  • Thread starter Nicklas Karlsson
  • Start date
K

Keith Thompson

Nicklas Karlsson said:
Oh, maybe "does not require an lvalue" was a bad statement, maybe
"does require an rvalue" would be more correct, I do think that the
sizeof operator takes the type of lvalues, and the type of rvalues, it
does not need the lvalue to evaluate to an rvalue, the lvalue doesn't
even need to designate valid object, it only needs to know the type
imposed by the lvalue.

Some context from the previous article would have made this clearer.

The phrase "does require an rvalue" doesn't make much sense.
The C standard uses the term "rvalue" to mean "the value of an
expression"; it mentions this in passing in a single footnote.
I find that any statement about C that uses the word "rvalue"
can be expressed more clearly without using the word "rvalue".

The sizeof operator, when its operand is an expression, determines the
type of the expression and yield the size, in bytes, of that type
(equivalently, the size of an object of that type). It doesn't matter
at all whether that expression is an lvalue or not. In most cases, the
expression isn't evaluated; it's merely analyzed (at compile time) to
determine its type. (The exception is when it's a variable-length
array.)
I guess my beef is with the term "evaluation", I do not quite
understand it. To me, it seems as an lvalue in a context that requires
an lvalue will partly evaluate at compile time (if its a normal memory
based variable for example), that is, being compiled into code that
identifies an object, but its not fully evaluated, at runtime the
offset decided for this variable will be used to calculate the
address.

What is this "offset" you're talking about? Offset of what, relative to
what?

When an lvalue (which, again, is a kind of expression) is evaluated
in a context that requires an lvalue, the result of the evaluation
is, in effect, the identity of the object that it designates.
For example, given:
x = 42;
``x'' is an lvalue that appears in a context that requires an lvalue.
Evaluating ``x'' in a non-lvalue context would yield the value
stored in the object named "x". Evaluating ``x'' in *this* context
identifies the object without reading its value; the identity of
the object is used to determine where the assignment operator will
store the value 42.

Whether this evaluation takes place at compile time or at run time
is not specified, and is not particularly important. If x is an
external variable, the resolution might take place at link time.
If the lvalue, rather than ``x'', is ``arr[rand()%MAX]'', then at
least some of the evaluation must take place at run time. In that
sense, it's not fundamentally different from non-lvalue evaluation.
But then we have register variables, I do not see any
possibility for it not to be fully evaluated at compile time, it knows
the register the lvalue uses, and it knows the type (therefore object
size, that is, part of the register used) of the lvalue. Here is where
I start going "is this really evaluation?" because I don't see that
any action is needed (no evaluation needed, if this isn't what you
call evaluation).

My advice: Don't worry about it. Expressions, whether they're
lvalues or not, are evaluated (or not), yielding either a value
or the identity of some object. Clever compilers can sometimes
pre-calculate some or all of the result, for example by replacing
``2 + 2'' with ``4''. In some contexts expressions are required to
be evaluated at compile time, for example case label expressions.
But that's mostly an implementation detail.
I'd be grateful is someone could tell me more about what evaluation
really means. MSDN says its:
* Computes a value
* Designates an object or function
* Generates side effects

That's about right.
...but does not say the nature of it, if the code generated could be
considered evaluation for example.

The *nature* of evaluation is that it computes a value, designates
an object or function, and/or generates side effects. Any code
generated is just an implementation-specific mechanism.

Are you assuming that a C expression, or an entire C program,
is a way to specify machine code? That's one way to think of
it, but not the best. A better way to think of it is that a C
expression or program is a way to specify certain *behavior*,
such as producing some output. The machine code is nothing more
or less than a mechanism used to achieve that goal.
 
N

Nicklas Karlsson

What is this "offset" you're talking about?  Offset of what, relative to

Sorry, I was drawing parallels to assembly mostly, seeing as a
variable will "have" an offset used to calculate an address relative
to, for example, the stack pointer.

My advice: Don't worry about it.  Expressions, whether they're
lvalues or not, are evaluated (or not)

So you are saying that expressions does not necessarily evaluate at
all? I was under the impression that all expressions always evaluate?
Is it that expressions does not have to evaluate, but an evaluated
expression always either yields a value or designates an object? The
point of my register variable example, was to show that it is only
compiled into code, that designates an object, but this compilation
into that code is not evaluation?
Are you assuming that a C expression, or an entire C program,
is a way to specify machine code?  That's one way to think of
it, but not the best.  A better way to think of it is that a C
expression or program is a way to specify certain *behavior*,
such as producing some output.  The machine code is nothing more
or less than a mechanism used to achieve that goal.

I suppose I think of expressions as a bit of both, I know that an
expression produces code when compiled, but I don't know if that is
evaluation, or part of evaluation, or not.
 
N

Nicklas Karlsson

Ops, I was gonna add one more line in the middle of my post, sorry for
double posting.

An expression can be compiled into code that designates an object,
this code designates an object, so to me the expression has evaluated
to designate an object.
 
K

Keith Thompson

Nicklas Karlsson said:
Sorry, I was drawing parallels to assembly mostly, seeing as a
variable will "have" an offset used to calculate an address relative
to, for example, the stack pointer.



So you are saying that expressions does not necessarily evaluate at
all? I was under the impression that all expressions always evaluate?

An expression in a function that's never called is not evaluated.

An expression that's in an if statement is never evaluated if the
condition is false. Likewise for various looping constructs and
the &&, ||, and ?: operators.

An expression that's the operand of sizeof is not evaluated (unless it's
a variable-length array). For example, this:

sizeof(printf("hello\n"))

will not print "hello".

Any expression in a program is never evaluated if you never run the
program.
Is it that expressions does not have to evaluate, but an evaluated
expression always either yields a value or designates an object?

Usually. An expression of void type doesn't yield a value or
designate an object; it may or may not have side effects.
The
point of my register variable example, was to show that it is only
compiled into code, that designates an object, but this compilation
into that code is not evaluation?

Evaluation is the process by which an expression yields a result,
designates an object, and/or generates side effects. The mechanism
by which that happens is almost entirely unspecified by the language.
Whether it involves generation of machine code, turning of brass
gears, or flapping of butterfly wings is not the concern of the
C language definition. (It is, of course, of great concern if
you want to understand a particular implementation, or how most
implementations work.)
I suppose I think of expressions as a bit of both, I know that an
expression produces code when compiled, but I don't know if that is
evaluation, or part of evaluation, or not.

I'm not sure there's a meaningful answer to that.
 
N

Nicklas Karlsson

An expression in a function that's never called is not evaluated.
An expression that's in an if statement is never evaluated if the
condition is false.  Likewise for various looping constructs and
the &&, ||, and ?: operators.

Good point, I never thought about it that way.
Evaluation is the process by which an expression yields a result,
designates an object, and/or generates side effects.  The mechanism
by which that happens is almost entirely unspecified by the language.
Whether it involves generation of machine code, turning of brass
gears, or flapping of butterfly wings is not the concern of the
C language definition.  (It is, of course, of great concern if
you want to understand a particular implementation, or how most
implementations work.)

I see, so the evaluation could involve generating code at compile time
and do some evaluation (like getting an address) at runtime for
example, as long as it produces some sort of result (designates an
object, generates side-effects or yields a value) it has evaluated,
and that is probably the case on most implementations? But its not
part of C, its up to the implementation?
 
K

Keith Thompson

Nicklas Karlsson said:
Good point, I never thought about it that way.


I see, so the evaluation could involve generating code at compile time
and do some evaluation (like getting an address) at runtime for
example, as long as it produces some sort of result (designates an
object, generates side-effects or yields a value) it has evaluated,
and that is probably the case on most implementations? But its not
part of C, its up to the implementation?

Pretty much.

Warning: Obsessively pedantic quibbling follows.

There are some odd corner cases that even the C standard's definition
of "expression" don't cover (C99 6.5p1: "An expression is a sequence
of operators and operands that specifies computation of a value,
or that designates an object or a function, or that generates side
effects, or that performs a combination thereof.")

For example, this:

(void)0

is an expression, but it neither specifies computation of a value,
designates an object or function, or has side effects. (The
subexpression 0 does compute a value, but that value is discarded
in the larger expression.)

It's useless but perfectly valid.

But that's just a special case, and not a particularly interesting
one.

Something I just noticed about the definition of "expression": for
the first clause, it says that it *specifies* computation of a value,
but for the other two clauses it says that it actually *performs* the
relevant actions. In all three cases, the action occurs only when
the expression is actually evaluated. It's a little inconsistent,
but not fatally so, and we all understand what was actually meant.
(And not every expression is "a sequence of operators and operands";
for example 0 has no operators and therefore no operands, but it's
still an expression.)
 
T

Tim Rentsch

Barry Schwarz said:
On Tue, 27 Apr 2010 13:04:26 -0700 (PDT), Nicklas Karlsson
[snip]
Take this for example (which is probably containts no-op's):
"*&i"

There is a special exception for the *& construct. Neither operation
is performed.

I suspect you're confusing this with &*. For the combination *&,
as in *&i, both operations are evaluated.
 
N

Nicklas Karlsson

For example, this:
    (void)0

Im gonna be a bit bold here, I might be way off, but here it goes: I
might have misunderstood something, but I got the idea that
expressions that are never used are never evaluated, and you take
"(void)0" as an example, sure this is an expression, but it can never
evaluate because it can never be used (trying to use this will result
in an invalid use of void expression), the expression itself must not
designate an object, produce a value or generate side effects (atleast
MSDN says its the evaluation that does this), I don't even think an
expression can do any of this, except designate an object (lvalue)
when unevaluated, it does however need to do 1 or more of the 3 things
when evaluated, but "(void)0" will never evaluate therefore it must
not produce a value, designate an object or generate side effects
In all three cases, the action occurs only when
the expression is actually evaluated.

Well, an lvalue is an expression that potentially designates an
object, and will evaluate to designate that object (or if no object
was designated by the expression the result of the evaluation of the
expression is not specified)
 
K

Keith Thompson

Please leave attribution lines in place.
Im gonna be a bit bold here, I might be way off, but here it goes: I
might have misunderstood something, but I got the idea that
expressions that are never used are never evaluated, and you take
"(void)0" as an example, sure this is an expression, but it can never
evaluate because it can never be used (trying to use this will result
in an invalid use of void expression), the expression itself must not
designate an object, produce a value or generate side effects (atleast
MSDN says its the evaluation that does this), I don't even think an
expression can do any of this, except designate an object (lvalue)
when unevaluated, it does however need to do 1 or more of the 3 things
when evaluated, but "(void)0" will never evaluate therefore it must
not produce a value, designate an object or generate side effects

(void)0 wasn't intended as an example of an expression that will never
be evaluated.

Let's make it part of a complete program:

int main(void)
{
(void)0;
return 0;
}

When the program executes, the expression ``(void)0'' *is* evaluated,
conceptually at least. That evaluation doesn't actually do anything.
In the abstract machine, the constant 0 is evaluated, yielding a result
of type int with value 0, and that result is then discarded, but all
that is very likely to be optimized out (i.e., the compiler generates no
code for it because it doesn't need to).

But again, this is a somewhat bizarre corner case. It's probably more
instructive to think about more ordinary expressions.

For example, consider:

int main(void)
{
int x;
x = 2 + 3;
return 0;
}

In the abstract machine, the values 2 and 3 are added together to
create the value 5, which is then stored in x. Given a reasonably
clever optimizing compiler, the expression 2 + 3 is likely to be
collapsed to 5, the assignment is likely to be eliminated because
the value of x is never used, and the storage for x is likely not
to be allocated because, again, it's never used.

Conceptually, the expressions ``x'' (an lvalue), ``2'', ``3'',
``2 + 3'', and ``x = 2 + 3'' are all evaluated, all yielding the
results and/or side effects that you'd expect. The method used to
evaluate them (in this case, doing nothing) is largely irrelevant
at the language level.
Well, an lvalue is an expression that potentially designates an
object, and will evaluate to designate that object (or if no object
was designated by the expression the result of the evaluation of the
expression is not specified)

Right. Were you agreeing or disagreeing with what I wrote?
 
N

Nicklas Karlsson

Please leave attribution lines in place.

I don't know what I'm doing wrong, I'm just removes the contents I
don't want to "quote", I don't know any other way of doing it.
When the program executes, the expression ``(void)0'' *is* evaluated,
conceptually at least.

Oh, I missed that, the code that is in an area that is going to be ran
conceptually evaluates, if it wasn't meant to be ran it would not
evaluate, well I did reserve myself for misunderstanding. :(
Right.  Were you agreeing or disagreeing with what I wrote?
I was thinking something along the lines with that expressions
themselfs can not do any of the things they will be evaluated to do,
except for designating objects.
 
T

Tim Rentsch

Nicklas Karlsson said:
I've been trying to swallow this entire thread, but I'm still not sure
about everything, another problem I have is that I spent today trying
to find answers and pretty much forgot the key questions, but I think
this is close enough to what I was wondering:

"An lvalue is an expression which potentially designates an object." -
This is the definition I got the impression of being right, and the
definition I used in my head when writing this.

About evaluation of lvalue...
If evaluation is a runtime thing and the offset of the variable who's
address is being fetched is known, does the lvalue evaluate then?

Take this for example (which is probably containts no-op's):
"*&i"

Here the compiler most likley knows i's offset, so maybe its -8 and
the compiler knows the type is "int", so it knows to start reading the
objects value at the address-offset -8 and to read sizeof(int) bytes.
Then what is the evaluation? Its not a runtime thing here right? Is
the evaluation the code it gets compiled into? If an lvalue already
identifies an object, why evaluate it? If the compiler does not know
what object the lvalue identifies, why is it said to identify an
object? Because it *does* in C? That is, in case of indirection... you
give it an address (or address to be) and the lvalue identifies an
object with that address and a type?

I'm skipping ahead a bit, if an lvalue always evaluates then this is a
question I want to ask:

About the indirection operator...
Basically, depending on context, the indirection operation may
evaluate to one of two different things, acctually, it always have to
evaluate to identify an object, if used where an lvalue is required,
it stops there, the evaluation is done, however when appearing in a
context that does not require an lvalue, the object identified will
have its value fetched, this means the expression evaluates to an
rvalue.

Is that correct?

Here's a way of thinking about it that may help.

An lvalue is basically an address. Or more technically, an
lvalue is an expression that at runtime will produce an address.
So when we have an lvalue expression, at runtime we need to
produce (either calculate, compute, or load) an address that is
the machine address of the object being designated.

Take the case of a local variable 'i', like what you mentioned.
The compiler knows at runtime that its offset is, as in your
example, -8 (based on the stack pointer, or frame pointer, or
something). But we still need to produce an actual machine
address. So we take the offset -8 and the runtime contents of
the register the -8 is based off of, add them together, and get
an actual address. In some machines this can be done with a
"load effective address" op code; in other machines it might
require an actual add operation of -8 and the base address held
in the register in question. These machine instructions are
"evaluating" the lvalue expression, ie, producing an actual
machine address for 'i' or whatever the lvalue expression is.

Of course, compilers are amazingly good at optimizing these low
level sorts of things, so the calculation of these lvalue
addresses may be subsumed into other operations to the point
where they seem to disappear completely. In principle, however,
there is a separate evaluation step for each lvalue expression,
and it produces a machine address (not just an offset) for
the operand in question. How that address is used depends on
the context (tbd next), but abstractly the address is produced
first, then used in different ways for different situations.

At the end you ask about the indirection operator. This question
corresponds to the situation mentioned in the last paragraph. In
particular, if we consider an lvalue expression, it might be used
on the right hand side of an assignment, or on the left hand side
of an assignment. (There are some other cases too, but basically
the other cases will boil down to being one of these two.) On
the _right_ hand side of an assignment, an lvalue expression is
evaluated to produce an address, and then the address is used to
load the value stored at that address. On the _left_ hand side
of an assignment, an lvalue expression is evaluated to produce an
address, but rather than loading a value, the address is used to
_store_ a value into the object at the address produced by
evaluating the (left hand side) lvalue expression. Of course,
the value to be stored is the value produced by evaluating the
right hand side of the assignment expression.

An important exception to the right hand side case for an lvalue
expression is when it is the operand of an & (address-of)
operator. In these cases, the lvalue expression is evaluated to
produce an address, but then the address is converted into a
pointer value, and that pointer value is what the & operator
produces. Of course, in most implementations, a "machine
address" and a "pointer value" are identical, but that doesn't
have to be true; a machine address is what the hardware uses
internally, and a pointer value is how the implementation has
chosen to represent address information in C objects. Usually
the representation of a pointer object in C will match how
addresses appear to the hardware, but sometimes that's not
feasible -- for example, a machine that can address only 64-bit
words, but where we want a C implementation where 'char' is only
8 bits; on a machine like this C pointer values and machine
addresses can't (and won't) exactly correspond.

Returning to your question about the indirection operator, it's
always true that an lvalue expression is evaluated to produce an
address, including the case where the lvalue expression is, for
example, '*p'. However, for most expressions not appearing on
the left hand side of an assignment operator [1], there is an
_additional_ rule that this address is then used to load the
value held in the object that the address refers to. So this
extra evaluation step is carried out for all lvalue expressions
(not just operands of the indirection operator) that occur
in a suitable right-hand-side context.

Does that make more sense now?

[1] the other exceptions are direct operands of 'sizeof', ++, --,
unary & (address-of), or the left hand side of a '.' operator.
(Also the 'sizeof' operator usually does not evaluate its operand
expression at all, including any subexpressions that operand
might contain.)
 
K

Keith Thompson

Nicklas Karlsson said:
I don't know what I'm doing wrong, I'm just removes the contents I
don't want to "quote", I don't know any other way of doing it.

When you create a followup, you should see a window containing the
entire parent article with each line preceded by "> ", with the whole
thing preceded by an attribution line such as:


When you're deleting content that you don't want to quote, just leave
that line alone.
 
N

Nicklas Karlsson

When you're deleting content that you don't want to quote, just leave
that line alone.

OK thanks for the information. :) I think I'm doing it right with this
post, if not I'm going to research Google for more information about
attribution lines.
 
K

Keith Thompson

Nicklas Karlsson said:
OK thanks for the information. :) I think I'm doing it right with this
post, if not I'm going to research Google for more information about
attribution lines.

You've got it!
 
L

lupux

When considering the definitions:
Object: A region of storage who's contents can be used to represent
values.
Lvalue: An expression designating such an object.

The problem:
Consider a normal variable, declared as "int i;" the variable we just
declared is an lvalue when used, "i" is an expression that has a type.
But an lvalue is an expression that even unevaluated designates an
object (in my understanding), "i" does only identify part of the
object, it only identifies the object type, it does not identify a
storage location, the storage location for "i" is not known until
runtime, when evaluated however "i" will designate an object, it will
have a storage location and a size (sizeof T), but this only happens
at evaluation, unevaluated "i" does not fully designate an object.

So I don't even understand how you can say that the expression itself
designates an object?
 
K

Keith Thompson

lupux said:
When considering the definitions:
Object: A region of storage who's contents can be used to represent
values.
Right.

Lvalue: An expression designating such an object.

Close enough. (If p is a null pointer, the expression ``*p'' is still
an lvalue even though it doesn't designate an object when it's
evaluated.)
The problem:
Consider a normal variable, declared as "int i;" the variable we just
declared is an lvalue when used, "i" is an expression that has a type.

The variable isn't an lvalue, assuming that by "variable" you
mean something like "declared object". The *expression* ``i''
is an lvalue. (The standard doesn't define the word "variable",
so I'm not entirely sure what you mean by it.
But an lvalue is an expression that even unevaluated designates an
object (in my understanding), "i" does only identify part of the
object, it only identifies the object type, it does not identify a
storage location, the storage location for "i" is not known until
runtime, when evaluated however "i" will designate an object, it will
have a storage location and a size (sizeof T), but this only happens
at evaluation, unevaluated "i" does not fully designate an object.

So I don't even understand how you can say that the expression itself
designates an object?

An lvalue designates an object *when it's evaluated*. Evaluation,
conceptually at least, takes place during execution. For example,
the expression ``arr[rand()%MAX]'' is an lvalue and designates some
object, but we don't know which one until run time.

I have no direct support from the standard for my claim that an
lvalue designates an object only when it's evaluated; it just makes
sense to me, and any other interpretation doesn't.

The standard is a little bit sloppy sometimes about distinguishing
between the properties an expression has before or during compilation
and the properties it has when it's evaluated udring execution.
I personally tend to think it should be more precise, but we can
only go so far in fixing imprecise language. The standard isn't,
and doesn't attempt to be, a mathematical formal specification of
the language; it's an English description with some formal elements.
Understanding what it says sometimes requires that we assume sanity
on the part of the authors. If it were made into a mathematical
formal specification, it could define the language without ambiguity.
But it would do so only for those few people who would be able to
read it -- a set that doesn't include most implementers or users.
 
N

Nicklas Karlsson

I think we have established that lvalues, when evaluated, always
potentially identifies objects, I have no problem with this for almost
all operators, but what about the & operator? I mean, does an address
per se identify an object? I see a memory based object as having a
size and a starting address.

My thoughts on it:
The & operator takes an lvalue as operand, the lvalue in this case
evaluates to an address (the starting address of an object), this
address will of course be loaded so we can use it. I can see how an
address identifies an object, but lets assume an address is an address
to a storage location capable of storing 1 byte of data, and the
object the lvalue *could* identify when evaluated in another context
is a region of storage capable of storing 4 bytes of data (the lvalue
evaluates to a specific instruction based on its imposed datatype/
size, so the size of the object is known, and in this case bigger than
the 1 byte object that address identifies), then the address only
identifies a 1 byte big object, that is sorta of a sub-object for the
bigger object that the lvalue *could,* in another context, evalute to
identify.

So too me, an lvalue might always evalaute to identify an object, but
not the entire object that the lvalue could identify in another
context, only the object at the starting address of the object the
lvalue could evaluate to identify.
 
K

Keith Thompson

Nicklas Karlsson said:
I think we have established that lvalues, when evaluated, always
potentially identifies objects, I have no problem with this for almost
all operators, but what about the & operator? I mean, does an address
per se identify an object? I see a memory based object as having a
size and a starting address.

The operand of the unary "&" operator must be an lvalue; it designates
the object whose address is to be taken. The expression ``&whatever''
is not an lvalue; its result is an ordinary value of some pointer type.

A declared object of a particular type has a number of attributes,
including its type and its address. The size is determined by
the type.

If you refer to its "starting address", I suggest that you're
thinking about this on too low a level. In C, an address is a value
of pointer type. The type specifies the size of the object. Given:
``int x;'', the expression ``&x'' is more clearly thought of as the
address of the entire object rather than as the "starting" address.
My thoughts on it:
The & operator takes an lvalue as operand, the lvalue in this case
evaluates to an address (the starting address of an object), this
address will of course be loaded so we can use it.

No, the lvalue does not evaluate to an address. Designating an object
and taking the address of an object are two quite different things.
(In the generated machine code, evaluating an lvalue might involve
computing an address, but we're talking about C, not machine code.)

An lvalue such as ``x'' or ``s.member'' might designate an object that
doesn't even have an address, such as a register object or a bit field.

I can see how an
address identifies an object, but lets assume an address is an address
to a storage location capable of storing 1 byte of data, and the
object the lvalue *could* identify when evaluated in another context
is a region of storage capable of storing 4 bytes of data (the lvalue
evaluates to a specific instruction based on its imposed datatype/
size, so the size of the object is known, and in this case bigger than
the 1 byte object that address identifies), then the address only
identifies a 1 byte big object, that is sorta of a sub-object for the
bigger object that the lvalue *could,* in another context, evalute to
identify.

I don't understand this. Can you give an example?
So too me, an lvalue might always evalaute to identify an object, but
not the entire object that the lvalue could identify in another
context, only the object at the starting address of the object the
lvalue could evaluate to identify.

An lvalue is always of some specific type. That type specifies
the size of the object that it designates.
 
N

Nicklas Karlsson

The operand of the unary "&" operator must be an lvalue; it designates
the object whose address is to be taken.  The expression ``&whatever''
is not an lvalue; its result is an ordinary value of some pointer type.

Yes, I do understand that the & operation results in an ordinary
value, in the end.
If you refer to its "starting address", I suggest that you're
thinking about this on too low a level.
No, the lvalue does not evaluate to an address.  Designating an object
and taking the address of an object are two quite different things.
(In the generated machine code, evaluating an lvalue might involve
computing an address, but we're talking about C, not machine code.)

Yes, I might be thinking of it at a to low level you are right. I was
thinking of how usually an lvalue evaluates to designate an object,
then that objects has its value read or has a value written to it. But
the lvalue required for the & operation most likely won't evaluate to
identify the entire object that it could in another context, but
merely takes the address to the objects first byte (that is, the
address identifies an N-byte(s) (usually 1 byte) big object.
I don't understand this.  Can you give an example?

Well, lets assume the following:
1. The variable is in memory
3. The variable is declared as int and an int is 4 bytes.
2. An address is an address to a region of storage that can store 1
byte of data

Now, if I did "var = 1;" the expression "var" would evaluate to
identify the object to where the value "1" should be written, if I do
"printf("%d", var);" the expression "var" would evaluate to identify
the object and read the objects value. Now if I did "&var" the lvalue
would evaluate to the address to the objects first byte, and since the
objects size is not used the address itself only identifies a 1 byte
big object, not the entire object that the lvalue *could* identify if
used in another context (and if the object was bigger than 1 byte).

(Sorry for this quoting style, I cut off the rest of the text already
and cannot go back)
"The operand of the unary "&" operator must be an lvalue; it
designates
the object whose address is to be taken."

Right, thats the entire point, the lvalue won't (unless the size if
the same as the object behind an address) evaluate to identify the
entire object (on my computers, it evaluates to an address), it will
only evaluate to identify parts of what's required to fully identify
an the object (it misses size, so the object's size isn't known,
therefore the object is not fully identified), namely the starting
address of the object.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,093
Messages
2,570,611
Members
47,230
Latest member
RenaldoDut

Latest Threads

Top