Address of an array = address of its 1st element: undecidable question?

C

Chris Torek

candide said:
The meaning is fuzzy, because -- even after correcting this to "the
value of an array" (or "the result of the `decay' of an array" or
however you want to express the idea of computing &array[0]) --
the types differ.

What about (void *) &array == (void *) &array[0]?

What about it? Consider:

#include <stdio.h>

int main(void) {
int equal;

equal = (int)3.1 == (int)3.2;
printf("%d %s %d\n", (int)3.1, equal ? "==" : "!=", (int)3.2);
return 0;
}

When compiled and run, this prints "3 == 3". And of course, three
*is* equal to three. That means 3.1 must be equal to 3.2, right? :)

The fundamental problem here is that we are comparing values of
different types, and to do that, we have to start by picking some
"common" type, convert both values to that common type, and then
compare the result. Each conversion *could* -- in this case, does
-- change the value in some subtle or not-so-subtle way. (On a
Lisp machine, changes may be fairly subtle, as they can involve
changing the type-tag bits without changing the rest of the
value-representation bits.)

When we compare the modified values, we can tell whether the modified
values are equal. Alas, we cannot tell whether this is because
the modification changed the values in the process. The only way
to find out is to observe the modification, which Standard C tells
us not to do. (We can do it anyway, by stepping outside the bounds
of Standard C, but then all we can say for certain is that *this*
implementation does whatever we just observed. Another implementation,
or even this one after it is modified someday in the future, need
not do the same thing.)

Sometimes, knowing what "this implementation" does is sufficient.
Quite often, knowing what "this implementation, that implementation,
and those 27 other implementations" do is sufficient. But none of
them tell us what *every* implementation, past or future, will
*have* to do. The "every implementation, past or future" is the
domain of the Standard (though even then, the Standard may do a
lousy job of that, since a future Standard could change things).
Can you then tell me what the standard means when
it says...

"The range of nonnegative values of a signed
integer type is a subrange of the corresponding
unsigned integer type, and the representation
of the same value in each type is the same."
^^^^^^^^^^

Either 'same value' is independant of type, or
above line makes no sense. Which is it?

You will have to ask the people who wrote the text of the Standard,
but I think this is a matter of slightly-sloppy phrasing.

We *do* know (from the Standard) that <type,value> pairs have
"representations": bit-patterns in what are, or at least look like,
binary, stored in memory, that we can take apart one "unsigned
char" at a time by doing:

T some_variable = some_value;
unsigned char *cp = &some_variable;
char *sep = "";
for (size_t i = 0; i < sizeof some_variable; i++) {
printf("%s%#x", sep, cp);
sep = " ";
}
putchar('\n');

which is likely to print things like:

0xc 0x40 0 0x01

for some value(s) of some type(s). The Standard does not promise
that there is a single unique representation for every value
(floating-point values in particular may see situations where
several different representations all mean the same "value",
especially for zero), but the phrase you have quoted above
tells us that for *integral* types (char, short, int, long,
long long, and their signed and unsigned variants), *nonnegative*
values in a signed type have a single representation, and it is
the same representation as the same value of an unsigned type.

More specifically, then:

#include <limits.h>
#include <stdio.h>

void print_the_representation(unsigned char *cp, size_t size, char *s) {
size_t i;
char *sep = "";

/* assumes CHAR_BIT is 8 (if not, still works but output is ugly) */
for (i = 0; i < size; i++)
printf("%s%2.2x", sep, cp);
printf("%s", s);
}

int main(void) {
short s;
unsigned short us;

for (s = 0; s < SHRT_MAX;) {
s++; /* so that range is [1..SHRT_MAX] inclusive */
print_the_representation((unsigned char *)&s, sizeof s, ", ");

us = s;
print_the_representation((unsigned char *)&us, sizeof us, "\n");
}
return 0;
}

Compile and run this program, and observe that the output is pairs
of comma-separated words, where each word is a hexadecimal expression
of the representations of "short" and "unsigned short" values in
the range [1..SHRT_MAX]. The Standard tells us that each word in
each such pair of words is identical.
 
K

Keith Thompson

Yevgen Muntyan said:
Richard said:
Peter Nilsson said: [...]
Can you then tell me what the standard means when
it says...

"The range of nonnegative values of a signed
integer type is a subrange of the corresponding
unsigned integer type, and the representation
of the same value in each type is the same."
^^^^^^^^^^

It means that the Standard isn't as picky about its use of the word "value"
as it should be. :)

It is picky all right. 1 and 1u have the same value,
the real number 1. 6.3.1 quite agrees with it, and
there is no reason to think otherwise. Quoted text
says so, by the way.

How do you reconcile this with the standard's definition of "value" in
C99 3.17?

value

precise meaning of the contents of an object *when interpreted as
having a specific type*

(emphasis added).
 
Y

ymuntyan

Yevgen Muntyan said:
Richard said:
Peter Nilsson said: [...]
Can you then tell me what the standard means when
it says...
"The range of nonnegative values of a signed
integer type is a subrange of the corresponding
unsigned integer type, and the representation
of the same value in each type is the same."
^^^^^^^^^^
It means that the Standard isn't as picky about its use of the word "value"
as it should be. :)
It is picky all right. 1 and 1u have the same value,
the real number 1. 6.3.1 quite agrees with it, and
there is no reason to think otherwise. Quoted text
says so, by the way.

How do you reconcile this with the standard's definition of "value" in
C99 3.17?

value

precise meaning of the contents of an object *when interpreted as
having a specific type*

(emphasis added).

I don't see a contradiction here. Consider a block of memory allocated
by malloc(), it is an object. It doesn't have a value; but it will
have
a value if you treat it as an object of particular type.

int *foo = calloc (sizeof(int), 1);
int a = /* the value is 0 here */ *foo;

The emphasized text is talking about that - raw bunch of bytes
(that is, an object) does not have a value. And a value is what
you get when you mix a type in. Note that above object may
as well be interpreted as an array of two shorts or an array
of four chars or some structure or whatever, you get different
values in those cases.

Yevgen
 
J

jameskuyper

Keith said:
How do you reconcile this with the standard's definition of "value" in
C99 3.17?

value

precise meaning of the contents of an object *when interpreted as
having a specific type*

The emphasized phrase merely implies that the relationship between the
contents of an object and the meaning of those contents depends upon
the type. A certain bit pattern, when interpreted as an unsigned char,
has a meaning that is the numerical value three. A very different and
much longer bit pattern, when interpreted as a long double _Complex,
also has the same meaning. Therefore, those two objects have the same
value, since their meaning is the same.

I've heard it claimed that the mathematical value of 3, considered as
an integer, is different from that of 3+0i, considered as a complex
number. I don't see that. As I understand it, in both cases, 3 is just
mathematical shorthand for 1+1+1, where 1 is defined as the identity
element under multiplication; a definition that fits 3 just as well as
3.0+0.0i.

Note: The standard's definition of 'value' is clearly inapplicable to
the value of an expression, because there is no corresponding object.
 
Y

ymuntyan

How do you reconcile this with the standard's definition of "value" in
C99 3.17?

precise meaning of the contents of an object *when interpreted as
having a specific type*
[snip]

Note: The standard's definition of 'value' is clearly inapplicable to
the value of an expression, because there is no corresponding object.

Doesn't it use language like "as if there was an object"? Like,
when there is an expression "1", it behaves as if that was an
int object with value of 1, and so on. Or isn't it at least the
very idea of "value of an expression"? (I.e. the definition is
clearly inapplicable as is, but is also clearly applicable after
*trivial* adjustment).
 
J

jameskuyper

Keith said:
It is picky all right. 1 and 1u have the same value,
the real number 1. 6.3.1 quite agrees with it, and
there is no reason to think otherwise. Quoted text
says so, by the way.
How do you reconcile this with the standard's definition of "value" in
C99 3.17?

precise meaning of the contents of an object *when interpreted as
having a specific type*
[snip]

Note: The standard's definition of 'value' is clearly inapplicable to
the value of an expression, because there is no corresponding object.

Doesn't it use language like "as if there was an object"?

No. It uses precisely the language given above. No more. No less.

Expressions are defined as "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." (6.5p1) There's nothing in that definition to
define the value computed "as if there was an object".

Incidentally, that definition has similar deficiencies. It doesn't
cover literal expressions like 3 or 256.3 or 'a', because without an
operator, literals are not operands. It has also been argued that the
use of the plural forms in that definition imply that something which
contains only one operator or only one operand doesn't qualify -
however, I think that's taking it a little too far. Luckily, the
standard also contains a grammar. From that grammer, it's clear that
the term "expression" was meant to correspond to the grammatical
construct of that same name as defined in 6.5.17p1. That construct
covers everything that we think of as a expression; it's clearly the
case that the definition in 6.5p1 was intended to match the
grammatical construct, and that conflicts between the grammar and that
definition should be resolved in favor of the grammar.

There's no corresponding help available for the concept of 'value'.

Like,
when there is an expression "1", it behaves as if that was an
int object with value of 1, and so on. Or isn't it at least the
very idea of "value of an expression"? (I.e. the definition is
clearly inapplicable as is, but is also clearly applicable after
*trivial* adjustment).

I have a pretty good idea of what I think "value" should (and does)
mean in the context of the C standard, though I'm not sure how to
express it in unambiguous standardese. The fact that objects can be
used to represent values plays no part in that concept, and I think it
was a mistake for the C standard to use the concept of an object in
it's definition of a 'value'. It's like defining a nation in terms of
the fact that nations can be represented by flags. If there's no flag,
is there no nation? If there's no object, is there no value? I think
that both questions have the same answer.
 
Y

ymuntyan

Keith Thompson wrote:
...
It is picky all right. 1 and 1u have the same value,
the real number 1. 6.3.1 quite agrees with it, and
there is no reason to think otherwise. Quoted text
says so, by the way.
How do you reconcile this with the standard's definition of "value" in
C99 3.17?
value
precise meaning of the contents of an object *when interpreted as
having a specific type*
Note: The standard's definition of 'value' is clearly inapplicable to
the value of an expression, because there is no corresponding object.
Doesn't it use language like "as if there was an object"?

No. It uses precisely the language given above. No more. No less.

Expressions are defined as "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." (6.5p1) There's nothing in that definition to
define the value computed "as if there was an object".

Incidentally, that definition has similar deficiencies. It doesn't
cover literal expressions like 3 or 256.3 or 'a', because without an
operator, literals are not operands. It has also been argued that the
use of the plural forms in that definition imply that something which
contains only one operator or only one operand doesn't qualify -
however, I think that's taking it a little too far. Luckily, the
standard also contains a grammar. From that grammer, it's clear that
the term "expression" was meant to correspond to the grammatical
construct of that same name as defined in 6.5.17p1. That construct
covers everything that we think of as a expression; it's clearly the
case that the definition in 6.5p1 was intended to match the
grammatical construct, and that conflicts between the grammar and that
definition should be resolved in favor of the grammar.

There's no corresponding help available for the concept of 'value'.

Like,
when there is an expression "1", it behaves as if that was an
int object with value of 1, and so on. Or isn't it at least the
very idea of "value of an expression"? (I.e. the definition is
clearly inapplicable as is, but is also clearly applicable after
*trivial* adjustment).

I have a pretty good idea of what I think "value" should (and does)
mean in the context of the C standard, though I'm not sure how to
express it in unambiguous standardese. The fact that objects can be
used to represent values plays no part in that concept, and I think it
was a mistake for the C standard to use the concept of an object in
it's definition of a 'value'. It's like defining a nation in terms of
the fact that nations can be represented by flags. If there's no flag,
is there no nation? If there's no object, is there no value? I think
that both questions have the same answer.

What I asked was if it describes what *expressions* mean using
objects,
e.g. that "1 + 1" means the same as if it was
"int tmp_obj = 1; int tmp_obj2 = 1; tmp_obj + tmp_obj2".
No idea why, but I'm used to think of complex expressions that
way, objects are easier to deal with than no-objects or something
like that. I do see now the standard uses combinations of values
and types, no objects involved (in cases like '2 + 2' of course,
when no objects are involved).

Values clearly exist without objects (if you can say "exist"
about a property), expressions have values. No idea if "zero"
exists alone, but it's not something I'd care about :)

Yevgen
 
K

Keith Thompson

Yevgen Muntyan said:
Richard Heathfield wrote:
Peter Nilsson said: [...]
Can you then tell me what the standard means when
it says...
"The range of nonnegative values of a signed
integer type is a subrange of the corresponding
unsigned integer type, and the representation
of the same value in each type is the same."
^^^^^^^^^^
It means that the Standard isn't as picky about its use of the
word "value" as it should be. :)
It is picky all right. 1 and 1u have the same value,
the real number 1. 6.3.1 quite agrees with it, and
there is no reason to think otherwise. Quoted text
says so, by the way.

How do you reconcile this with the standard's definition of "value" in
C99 3.17?

value

precise meaning of the contents of an object *when interpreted as
having a specific type*

(emphasis added).

I don't see a contradiction here. Consider a block of memory
allocated by malloc(), it is an object. It doesn't have a value; but
it will have a value if you treat it as an object of particular
type.

int *foo = calloc (sizeof(int), 1);
int a = /* the value is 0 here */ *foo;
Right.

The emphasized text is talking about that - raw bunch of bytes
(that is, an object) does not have a value. And a value is what
you get when you mix a type in. Note that above object may
as well be interpreted as an array of two shorts or an array
of four chars or some structure or whatever, you get different
values in those cases.

Agreed.

But the question is whether the expressions 1 and 1u have the same
"value". Since the standard defines "value" in terms of "object",
it's not as helpful in answering that question as I'd like it to be.
But a reasonable extension of the standard's definition of "value"
would, I think, preserve the idea that a value's *type* is part of its
identity. This implies that 1 and 1u have different values because
they have different types (even though they have the same, um,
"numerical value").

Consider this:

int zero = 0;
void *null_ptr = 0;

Do zero and 0 have the same value? (I'd say yes.)
Do 0 and null_ptr have the same value? (Hmm.)
Do zero and null_ptr have the same value? (Certainly not.)

Also, consider that the way C determines whether two values are the
same is with the "==" operator. That operator cannot directly compare
1 and 1u; it must convert one of the operands to the other's type
first. (This isn't my strongest argument; for example, structs have
values but they can't be compared with "==".)

In general, I think that if you want to say whether values of
differing types are "the same", you first have to convert them to a
common type.

On the other hand, saying that 1 and 1u have the same value, even if
it's not strictly correct, can be a convenient shorthand.
 
C

candide

pete a écrit :
The expressions (void *) &array and (void *) &array[0] have the same
type - i.e. void *. Therefore, they /can/ have the same value (and may
well have).

((char *)&array) and ((char *)&array[0]) have the same value.


Prove it !
 
K

Keith Thompson

What I asked was if it describes what *expressions* mean using
objects,

It doesn't. (Well, one could argue that the use of the word "value"
in the definition of "expression", combined with the fact that the
definition of "value" depends on having an object, could imply that,
but I'm 99% sure that wasn't the intent.)

For example, given the expression
42
there's no implication that there needs to be an object to hold the
value of the expression.
 
C

Chris Torek

Values clearly exist without objects [in C] ...

Right. The problem is, values "evaporate" if you fail to
store them in objects, so in order to do anything useful with
the values, you eventually have to put them in objects. It
is at this point that the value (now stored) acquires a
representation -- and the representation is the only thing
you can really inspect, in the end. This means you *cannot*
*tell* how the value is represented when it is not in an object
(e.g., when it is in a machine register).

There is an actual example of where this matters: the x86 CPU, with
any C compiler that has 32-bit "float" and 64-bit "double" and
"long double" (i.e., where long double is not 80 bits). Actual
operations happen in the FPU, on 80-bit "registers" (x86 FPU-stack
entries -- these are in fact registers in hardware; they just happen
to be addressed via stack notation). You can do things like:

push 1st 32-bit float onto stack
push 2nd 32-bit float onto stack
add (pops top two stack entries, adds, pushes result)
pop-and-store stack-top as 32-bit float

The actual add is done in an 80-bit representation, yet no matter
what you do in C code, you can only see two 32-bit operands and a
32-bit result. You can use double or long double and you see only
64-bit operand with a 64-bit result. The *actual* values, as kept
on the FPU stack, are not available to the C programmer, only the
"shadow" versions in RAM! (Note, I am deliberately glossing over
the complexities of x86 FPU stacks here, and of course you can
resort to assembly code to save the actual in-FPU representations
and then look at those -- but to do that, you have to bypass the
C language.)

This means that we can even build CPUs that work in something other
than binary, and still program them in C, by having the "load" and
"store" operations that transfer values in and out of the CPU also
do whatever steps are required to make it *look like* the CPU works
with binary values. (There are additional constraints: we have
to make bitwise & | ^ work right, we have to make shifts look
binary, and so on. Standard C spells out what we, as compiler
writers, would have to do with this CPU.)
 
K

Keith Thompson

CBFalconer said:
Just look at what is going on in the (a < b) conditional
evaluation. The system loads a, and says "aha, I have an unsigned
value. What am I comparing it to?". It then loads b, and says
"aha, a signed value. I can't compare these. So I have to modify
one, and the only one that is modificable to the other type is the
int. So take its unsigned value".

Let me expand on your "the only one that is modificable to the other
type is the int". Either *type* can be converted to the other. For
either conversion, there's a possibility that the numeric value of the
converted operand cannot be represented in the target type.

The standard *could* have specified that the unsigned operand is
converted to signed int, but the committe decided to convert from
signed to unsigned, probably at least in part because the result of
that conversion isn't implementation-defined.
 
B

Ben Bacarisse

Keith Thompson said:
It's a minor flaw in the definition of "value".

OK. I can see how /you/ see it that way but as a definition to be used
to explain (to someone learning all this) the flaw is a little more
than minor -- it is a definition that does not apply. Neither
expression in question is (or designates) an object so there are no
contents to be interpreted.

Of course it can be fixed (but see below) but I think the fact that it
has to be extended and qualified is more than a minor flaw. "Fatal
flaw" was probably too strong. If you want to stick with "minor", in
the context of someone learning C, than I won't press the matter but I
will beg to differ.
(It's not the only
definition in the standard that provides an example of the term being
defined rather than an exhaustive definition).

<aside>
Continuing your aside, I think the problem of the definition is a
little deeper than that. With the above definition, in mind some
phrases just seem daft:

"The meaning of a value stored in an object or returned by a
function is determined by the type of the expression used to access
it."

This is obviously intended to reinforce the definition and should
probably have been something like "The precise meaning of the data
stored in an object or returned by a function is determined by the
type of the expression used to access it. This is called the value of
the object or function." I say "probably" because I may have missed
the intent. What is clear is that one should not talk about the
meaning of a value if a values is defined as the precise meaning of
something else.

Then there is this:

"A constant is a primary expression. Its type depends on its form
and value, as detailed in 6.4.4."

That is circular since its value depends on the type. Of course, the
circularity can be broken by "trying" the different types in section
6.4.4 but even that is complicated because 6.4.4 says:

"The type of an integer constant is the first of the corresponding
list in which its value can be represented."

and earlier:

"Each constant shall have a type and the value of a constant shall be
in the range of representable values for its type."

It is much easier to resolve these three if we take "value" to have the
looser mathematical meaning.

Finally, the standard talks about "copying values". I don't see how
values in the sense of "precise meanings..." can be copied. I think
the standard does not take its own definition of value too seriously.
It's clear that
expressions do have values; see the standard's (also incomplete)
definition if "expression" in 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.

I think it's sufficiently clear for purposes of this discussion that a
"value", whether it's contained in an object or results from
evaluating an expression, has a specific type. I don't think it's
possible to discuss this stuff consistently without making that
assumption.

I agree, but I don't think the standard's definition makes that
clear. It suggests that objects (and by your extension the results of
expressions) have a value only "when" interpreted. Of course, at every
point in a program, every object and expression has some effective
type which is the one used to "induce" the value, but I would prefer
that the linkage be explicit in the definition.

I think it is much simpler to view types as set of values. Objects
contain representations of values, and expressions (by dint of having
a value) have a type (the set of which the result is a member). Then,
questions about values being the same or not would be determined by the
mathematical structure of the types -- some languages use disjoint
unions so that 1 and 1.0 are not "the same value" while in others the
representable integers are stated to be a subset of the representable
floats. Of course, I have no idea if the language of the standard
could be re-cast in this form.
 
B

Ben Bacarisse

Yevgen Muntyan said:
I mean the definition of the term "value of an object"
from the standard.

OK. Yes one could certainly use that definition. I don't think it is
without it problems. I've detailed some of these problems in a reply
to Keith Thompson elsewhere but despite these it is workable. In this
context, the main reason I would not cite it is that is does not
apply, since it talks about objects and neither expression in question
was an object.

I see that the discussion of that has already moved on, so this point
is probably moot, but my real objection to using it is that is does
not help answer the question that the OP had. The OP was confused by
people using phrases like "bit value" and "the addresses are the
same". Explaining what these terms meant and the ways in which they are
consistent with, for example, Keith Thompson's more formal quote
seemed more helpful.
Could you provide an example perhaps?

I've given some in my other answer. It is not specifically the phrase
"same value" that is problem it is just that the standard does not
seem convinced by its own definition.
Really, once
you don't think that a "value of an array" can mean
value of the pointer it's converted to (namely, of
the result of the corresponding expression, or
whatever it is in legalese), then you don't have
any problems with the term "value" and its use in
a phrase "same value".

Yes, I though that was clear in my answer. I am sorry if it was not.
 
Y

ymuntyan

Richard Heathfield wrote:
Peter Nilsson said:
[...]
Can you then tell me what the standard means when
it says...
  "The range of nonnegative values of a signed
  integer type is a subrange of the corresponding
  unsigned integer type, and the representation
  of the same value in each type is the same."
         ^^^^^^^^^^
It means that the Standard isn't as picky about its use of the
word "value" as it should be. :)
It is picky all right. 1 and 1u have the same value,
the real number 1. 6.3.1 quite agrees with it, and
there is no reason to think otherwise. Quoted text
says so, by the way.
How do you reconcile this with the standard's definition of "value" in
C99 3.17?
    value
    precise meaning of the contents of an object *when interpreted as
    having a specific type*
(emphasis added).
I don't see a contradiction here. Consider a block of memory
allocated by malloc(), it is an object. It doesn't have a value; but
it will have a value if you treat it as an object of particular
type.
int *foo = calloc (sizeof(int), 1);
int a = /* the value is 0 here */ *foo;
Right.

The emphasized text is talking about that - raw bunch of bytes
(that is, an object) does not have a value. And a value is what
you get when you mix a type in. Note that above object may
as well be interpreted as an array of two shorts or an array
of four chars or some structure or whatever, you get different
values in those cases.

Agreed.

But the question is whether the expressions 1 and 1u have the same
"value".  Since the standard defines "value" in terms of "object",

No it doesn't, that's the thing. It defines value *of object*, it
doesn't define the human language term "value". I.e. it defines
what it means for a C object to have value 1, not what value 1
is.
it's not as helpful in answering that question as I'd like it to be.
But a reasonable extension of the standard's definition of "value"
would, I think, preserve the idea that a value's *type* is part of its
identity.  This implies that 1 and 1u have different values because
they have different types (even though they have the same, um,
"numerical value").

Numerical value *is* the value.
Consider this:

    int zero = 0;
    void *null_ptr = 0;

Do zero and 0 have the same value?         (I'd say yes.)
Yes.

Do 0 and null_ptr have the same value?     (Hmm.)
No.

Do zero and null_ptr have the same value?  (Certainly not.)

No.

0 is an integer constant, it has value 0. zero is a variable
of type int, with value 0. null_ptr is a pointer variable,
with value "null pointer". (For nuts, zero is an identifier
designating an object of type int with value 0, etc)
Also, consider that the way C determines whether two values are the
same is with the "==" operator.  That operator cannot directly compare
1 and 1u; it must convert one of the operands to the other's type
first.

Right, it's how operators work. How does it imply or does not
imply that 1 and 1u have different values? The have the same
values simply because they do, the value "real number 1".
 (This isn't my strongest argument; for example, structs have
values but they can't be compared with "==".)

In general, I think that if you want to say whether values of
differing types are "the same", you first have to convert them to a
common type.

But this common type is not necessarily a C type. For numbers,
this common type is "some set of complex numbers together with
some set of special values, nans and infinities". One is one,
regardless of what type is the object.
On the other hand, saying that 1 and 1u have the same value, even if
it's not strictly correct, can be a convenient shorthand.

And so it is strictly correct. The value is "real number 1".
Or what's the value of 1 and what's the value of 1u?

Yevgen
 
Y

ymuntyan

Values clearly exist without objects [in C] ...

Right.  The problem is, values "evaporate" if you fail to
store them in objects,

But these values are not the values the standard is talking
about. Good or bad, it's written this way, there
are values first (like "1.5"), and then those values may be
stored in objects.
so in order to do anything useful with
the values, you eventually have to put them in objects.  It
is at this point that the value (now stored) acquires a
representation -- and the representation is the only thing
you can really inspect, in the end.
 This means you *cannot*
*tell* how the value is represented when it is not in an object
(e.g., when it is in a machine register).

Right, because C doesn't know what "representation" means
when there is no object.
There is an actual example of where this matters: the x86 CPU, with
any C compiler that has 32-bit "float" and 64-bit "double" and
"long double" (i.e., where long double is not 80 bits).  Actual
operations happen in the FPU, on 80-bit "registers" (x86 FPU-stack
entries -- these are in fact registers in hardware; they just happen
to be addressed via stack notation).  You can do things like:

    push 1st 32-bit float onto stack
    push 2nd 32-bit float onto stack
    add (pops top two stack entries, adds, pushes result)
    pop-and-store stack-top as 32-bit float

The actual add is done in an 80-bit representation, yet no matter
what you do in C code, you can only see two 32-bit operands and a
32-bit result.  You can use double or long double and you see only
64-bit operand with a 64-bit result.  The *actual* values, as kept
on the FPU stack, are not available to the C programmer, only the
"shadow" versions in RAM!

But those actual values are the "hardware values". The values
in your C program (when you forget about real life and stuff
like that) are coming from appendix X or from whatever floating
point representation you are using. The values are exactly the
values which correspond to those 32-bit sets, no matter what's
in hardware. There is no hardware as far as C is concerned
after all. Close to hardware damn it!
 (Note, I am deliberately glossing over
the complexities of x86 FPU stacks here, and of course you can
resort to assembly code to save the actual in-FPU representations
and then look at those -- but to do that, you have to bypass the
C language.)

This means that we can even build CPUs that work in something other
than binary, and still program them in C, by having the "load" and
"store" operations that transfer values in and out of the CPU also
do whatever steps are required to make it *look like* the CPU works
with binary values.  (There are additional constraints:  we have
to make bitwise & | ^ work right, we have to make shifts look
binary, and so on.  Standard C spells out what we, as compiler
writers, would have to do with this CPU.)

And so you would have to make those "soft" values "exist",
regardless of what "hard" values are really there :)

Yevgen
 
K

Keith Thompson

No it doesn't, that's the thing. It defines value *of object*, it
doesn't define the human language term "value". I.e. it defines
what it means for a C object to have value 1, not what value 1
is.

I disagree. C99 3.17 is the standard's definition of the word "value":

value
precise meaning of the contents of an object when interpreted as
having a specific type

This isn't a definition of the phrase "value of an object", it's a
definition of the word "value". (And the flaw in that definition is
that it doesn't define the value of an expression.)
Numerical value *is* the value.

My reasoning is that, since the value of an object makes sense only in
terms of that object's type, it's reasonable to assume that the value
of an expression also makes sense only in terms of that expression's
type. 3 and 3.0 are two very different things.

[...]
But this common type is not necessarily a C type. For numbers,
this common type is "some set of complex numbers together with
some set of special values, nans and infinities". One is one,
regardless of what type is the object.

Again, I disagree. 1 and 1.0 are very different things. They're not
the *same* value, they're numerically equivalent values. At least
that's the way I think of it.
And so it is strictly correct. The value is "real number 1".
Or what's the value of 1 and what's the value of 1u?

The most concise way to express their values in C is 1 and 1u, but of
course that's not very illuminating. I'd say that their values are
(1 of type int) and (1 of type unsigned int).

On the other hand, I think one could have a consistent description of
the language in which the value of an expression doesn't depend on its
type, or, more precisely, that the type is not a component of the
value. In other words, that the value of an arithmetic expression
*is* the numeric value of the expression. But I think you'd still
have to say that two *objects* of distinct types have distinct values,
given the standard's definition of the word "value". I just think
that a model in which a value depends on its type is more consistent
with the wording and intent of the standard. But since the standard
doesn't say what it means for two values to be "the same", that's not
the only possible model.
 
B

Bartc

Richard Heathfield said:
Chris Torek said:
Values clearly exist without objects [in C] ...

Right. The problem is, values "evaporate" if you fail to
store them in objects, so in order to do anything useful with
the values, you eventually have to put them in objects.

Alternatively, to extend the life of these objectless values, you can run
the processor at a lower clock speed or add an extra cooling fan.

How would the extra fan help?
 
C

candide

Ben said:
> If you include the notion of type in that of value, then the answer is
> "no". If you don't then the answer can be a qualified "yes". The
> qualification is made very clear by most of the quotes ("the bit
> values are the same", "they compare equal when converted to void *")
> but even when it is glossed over, there is no contradiction.

The contradiction I referred to was the first quote from Larry Jones but
this is not my point.

About the wording "the bit values are the same", did you notice that DMR
was suggesting that the bit value coincidence was not a portable
property, for being restricted to the "usual implementation" as he said
himself ? By the way, what exactly is the "usual implementation" ?

And what is exactly meant by "the bit values are the same" ? Does this
mean that my_array and &my_array yield the same bit representation ? If
so, does the standard guarantee such a thing ? I don't think so :

-------------------- 8< -----------------------------
§6.2.5
All pointers to structure types shall have the same representation and
alignment requirements as each other. All pointers to union types shall
have the same representation and alignment requirements as each other.
Pointers to other types need not have the same representation or
alignment requirements.
-------------------- >8 -----------------------------



Larry Jones put on the same level the correspondance between an array
address vs its first member address and the analog correspondance for
structures.
Why does the Standard take care of the structure case and even doesn't
mention the array case ? I recall the Standard says :

-------------------- 8< -----------------------------
§6.7.2.1
A pointer to a structure object, suitably converted, points to its
initial member (...) and vice versa.
-------------------- >8 -----------------------------

How does one adapt this situation to the array case ? For instance,
declaring

int t[3];

can we expect (int *)&t will always equal to &t[0] ? and conservely, &t
will equal to (int (*)[3])&t[0] ?


> about them. If you were to permit me, I'd go on to say that they have
> values that convert to equal void *s. The C standard is very clear
> that a pointer to a whole object and pointer to one of its initial
> sub-objects must compare equal (provided you convert the pointers so
> that comparison is permitted) so the pointers have the same value in
> that limited sense.

I suppose you are referring to the following excerpt of the Standard :

-------------------- 8< -----------------------------
Two pointers compare equal if and only if both are null pointers, both
are pointers to the same object (including a pointer to an object and a
subobject at its beginning) or function, [...]
-------------------- >8 -----------------------------

The Standard doesn't define what is meant by a subobject. I can imagine
that an array element is a subobject of the whole array. But how on
earth pointers to object that doesn't share the same type can compare
equal ?

It is worth mentionning that the last quote above is not exactly the
same as in the C90 standard wich omits the reference to the case of a
subobject :

-------------------- 8< -----------------------------
If two pointers to object or incomplete types compare equal, they
point to the same object. If two pointers to functions compare [...]
-------------------- >8 -----------------------------
 
B

Ben Bacarisse

candide said:
The contradiction I referred to was the first quote from Larry Jones but
this is not my point.

Sorry, I don't see the contradiction. I though the historical
reference had misled you. Let me pay more attention to the quote,
then. He says:

| I'm not aware of any definition (or even description) of the C language
| that said that taking the address of an array was equivalent to taking
| the address of the first member of the array.

What does "equivalent to" mean? I don't know for sure, but since the
two operations produce different types it seems a stretch to say he is
at odds with any of the other writers. The current standard says that
when suitable converted they will compare equal, but I am sure he know
that!
About the wording "the bit values are the same", did you notice that
DMR was suggesting that the bit value coincidence was not a portable
property, for being restricted to the "usual implementation" as he
said himself ?

Yes I did.
By the way, what exactly is the "usual implementation"
?

Presumably he means when the address space is "flat". A segmented
architecture could produce different bit values, maybe, which is fine
provided that they compare equal using == after conversion. On such a
system, after

int data[10];
int *ip = &data[0]; /* or just = data, of course */
int (*ap)[10] = &data;

we could have memcmp(&ip, &ap, sizeof ip) != 0 provided that
(void *)ip == (void *)ap.

If you really must know exactly he means, you'll have to ask him, but
do you think was saying something that was at odds with accepted
wisdom?
And what is exactly meant by "the bit values are the same" ?

I would take it to mean what you get when viewing a stored value as an
array of bytes (an unsigned char [n]). The memcmp example is a short
hand. We could write out:

unsigned char ipbv[sizeof ip];
unsigned char apbv[sizeof ap];
memcpy(ipbv, &ip, sizeof ipbv);
memcpy(apbv, &ap, sizeof apbv);
/* and not test: */
sizeof ipbv == sizeof apbv && memcmp(ipbv, apbv, sizeof ipbv) == 0

but that is just too long-winded.
Does this
mean that my_array and &my_array yield the same bit representation ?

No. It means he thinks they would using the "usual implementation".
You then can either say his idea of usual is wrong or use it to find
out what he thinks of as usual. Your choice.
If so, does the standard guarantee such a thing ? I don't think so :

-------------------- 8< -----------------------------
§6.2.5
All pointers to structure types shall have the same representation and
alignment requirements as each other. All pointers to union types
shall have the same representation and alignment requirements as each
other.
Pointers to other types need not have the same representation or
alignment requirements.
-------------------- >8 -----------------------------

Absolutely. This tells me what DR thinks is usual, not that he is wrong.
Larry Jones put on the same level the correspondance between an array
address vs its first member address and the analog correspondance for
structures.
Why does the Standard take care of the structure case and even
doesn't mention the array case ? I recall the Standard says :

-------------------- 8< -----------------------------
§6.7.2.1
A pointer to a structure object, suitably converted, points to its
initial member (...) and vice versa.
-------------------- >8 -----------------------------

How does one adapt this situation to the array case ? For instance,
declaring

int t[3];

can we expect (int *)&t will always equal to &t[0] ? and conservely, &t
will equal to (int (*)[3])&t[0] ?

Yes, I think so. See the definition of ==.
about them. If you were to permit me, I'd go on to say that they have
values that convert to equal void *s. The C standard is very clear
that a pointer to a whole object and pointer to one of its initial
sub-objects must compare equal (provided you convert the pointers so
that comparison is permitted) so the pointers have the same value in
that limited sense.

I suppose you are referring to the following excerpt of the Standard
:

-------------------- 8< -----------------------------
Two pointers compare equal if and only if both are null pointers, both
are pointers to the same object (including a pointer to an object and
a subobject at its beginning) or function, [...]
-------------------- >8 -----------------------------

Ah. I see you already have that in mind.
The Standard doesn't define what is meant by a subobject. I can
imagine that an array element is a subobject of the whole array. But
how on earth pointers to object that doesn't share the same type can
compare equal ?

They can if the types are compatible. I am not really sure anymore
what your point is. Do you disagree that, suitable converted, a
pointer to an array and a pointer to the first element of an array
will compare equal? If so, I think you are wrong. If you think
someone has said they won't, then who?
It is worth mentionning that the last quote above is not exactly the
same as in the C90 standard wich omits the reference to the case of a
subobject :

-------------------- 8< -----------------------------
If two pointers to object or incomplete types compare equal, they
point to the same object. If two pointers to functions compare [...]
-------------------- >8 -----------------------------

I suspect the addition was deliberate.
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top