K
Keith Thompson
Nicklas Karlsson said:Yes, I do understand that the & operation results in an ordinary
value, in the end.
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.
Perhaps I'm misunderstanding you, but this is incorrect.
Let's assume sizeof(int)==4. Given:
int arr[10];
int i = 5;
the expression ``arr'' is an lvalue that designates an
element of the array. This lvalue is of type int, which means
that it designates an object of type int, whose size is 4 bytes.
Applying unary "&" to this value gives us ``&arr'', a non-lvalue
expression whose value is of type int*. It is the address of the
int object, *not* the address of its first byte. (If you wanted
the address of its first byte rather than of the entire int object,
you could write ``(char*)&arr'', among other possibilities.)
Well, lets assume the following:
1. The variable is in memory
Ok.
3. The variable is declared as int and an int is 4 bytes.
Ok. (You swapped 2 and 3, but that doesn't matter.)
2. An address is an address to a region of storage that can store 1
byte of data
And this is where you go wrong. I think you're using the term
"address" to refer to a machine-level address. That's not what the
word "address" means in C, and in particular it's not what the unary
"&" operator yields.
A C "address" is a value of pointer type. A pointer type always
specifies a type that it points to (possibly void, possibly
incomplete, possibly a function type, but it's always some C type).
C pointer values are typically *implemented* as machine-level
addresses (though I could cite exceptions to that), but logically a
C pointer is always a pointer to something of some particular type,
and if the pointed-to type is an object type then it has a specific
size associated with it. That size isn't 1 byte unless it just
happens to be a type whose size is 1 byte.
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.
Right. In the first case, the lvalue ``var'' appears in a context
that requires an lvalue, so it designates the object. In the
second it appears in a context that doesn't require an lvalue,
so it's "converted to the value stored in the designated object
(and is no longer an lvalue)" (C99 6.3.2.1p2).
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).
No, ``&var'' yields the address *of the entire object*, and is of type
pointer-to-int, *not* pointer-to-byte.
Now the generated machine code and in-memory representation for a
pointer to an int is likely (but by no means certain) to be identical to
those for a pointer to the first byte of the same int. Type information
is discarded during the process of translating C source code to machine
code. Similarly, the generated code and in-memory representation for
float x = 3.1415927;
and
unsigned int x = 0x40490fdb;
are likely to be identical, but *in C* they're conceptually very
different. We still say that x is of type float in the first case
and of type unsigned int in the second.
(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.
Can you provide a concrete example, in C code, where an lvalue
designates the first byte of an object rather than the entire
object? What exactly do you mean when you say that it designates
the first byte?
(A minor point: I prefer to use the term "designate" rather than
"identify". They probably mean the same thing, but the standard
uses the term "designate".)