Re: A question on string literals



Chris Torek <nospam@xxxxxxxxx> writes:

> >> Richard Heathfield wrote:
> >>>>> [Array-to-pointer] decay happens only in value contexts,
>
> >pete wrote:
> >> Where are you getting that from?
>
> In article <ddopvu$f6k$1@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>
> Richard Heathfield <sorry.spammers@xxxxxxxxxxxxxxxxxxxxxxxxx> wrote:
> >Well, I must admit I was getting it from Chris Torek's constant incantations
> >of "The Rule", and perhaps I was over-interpreting it. The fact remains
> >that the conversion you expect is not guaranteed by the Standard for the
> >simple reason that the code itself violates a constraint.
>
> Indeed, "The Rule" and the C standards (both of them) are not
> literally the same -- but they *are* isomorphic, i.e., both give
> the same result. I think my formulation is easier to understand,
> as well, because we need the idea of "value context" vs "object
> context" in the first place, so that we can figure why:
>
> int x, b;
> ...
> x = b;
>
> copies b's *value* to the *object* named x.
>
> If x used to be 3 before the assignment, and b is 7, why does this
> set x to 7, instead of setting b to 3, or setting 3 to 7, or setting
> 7 to 3? (Of course, only two of those four possibilities even make
> sense.) The answer is that the "=" operator demands an object on
> its left, and a value on its right. The context on the left of
> the "=" is an "object context", and the context on the right is a
> "value context". Put down a value when something needs a value
> and there is no problem:
>
> x = 3;
>
> Here x is an object and 3 is a value (of the correct type), so this
> sets x to 3. Name an object on the right, though, and the operation
> automatically fetches the object's value:
>
> x = b;
>
> so if b was 7, x becomes 7 too.
>
> Once you understand the idea of "object context" and "value context",
> you simply have to memorize which operators have which context(s):
>
> &foo - object context
> sizeof foo - object (or maybe even "sizeof") context
> foo + bar - two value contexts
> foo = bar - one object context, one value context
> ++foo - object context
>
> and so on.

A difficulty with the above is that the operand of sizeof
isn't an object context: any expression can be used as the
operand of sizeof [1], not just an lvalue expression. Also,
note a difference in behavior: usually,

sizeof &*p == sizeof p

if 'p' is a pointer (eg, to int), but (again, usually)

sizeof &*array != sizeof array

if 'array' is an array, even though both equalities hold if
the 'sizeof's are taken out.

Of course, it's important to understand the distinction
between "object context" and "value context", but trying to
use that distinction to explain what happens with arrays in
conjunction with sizeof seems like a strain. An expression
of array type simply behaves differently than expressions of
other types. It isn't that hard to remember the exception
cases for when an array expression doesn't convert to a
pointer; there are after all only three of them.

Incidentally, note that the distinction between object
context and value context also doesn't work very well for
the third exceptional case for array-type non-conversion,
which is that of a string literal used to initialize an
array:

char *p = "blah"; /* conversion */
char s[] = "blah"; /* no conversion */

On the face of it both instances of "blah" look like they
ought to be object contexts.

=====
[1] Subject to the usual need for parentheses around
operators of lower precedence, and the need to avoid
function types and incomplete types.


> Given all of that, applying The Rule becomes easy, and whenever
> the result is not "this makes no sense and a diagnostic is required",
> it gives the same result as the more complicated way the C standards
> put it.

It seems easier (at least to me) to remember that array
expressions always convert to pointers, except when they are
the operand of sizeof or address-of operators (or string
literals used to initialize an array).

That the conversion yields a value, rather than being an
object designator, suffices to explain (and without having
to remember anything extra) why an array expression can't be
assigned to or incremented, any more than the value of a
function call

f() = 3; /* WRONG! */
f() ++; /* WRONG! */

can be assigned to or incremented. Just knowing that
the array conversion is happening is enough to explain
and understand the behavior here.

Certainly there are places where the C standards documents
give explanations that are more complicated than they need
to be. IMO however the rule for when arrays are or aren't
converted to pointers isn't one of them.
.



Relevant Pages

  • Re: Datagrid with search capabilities, how to implement it?
    ... We have a datagridview in a form and want to implement search capabilities ... Creates a currencymanager bound to the same binding context of the ... Uses the datatable.Selectmethod on the SortTable to get a datarow array ...
    (microsoft.public.dotnet.framework.adonet)
  • Re: string concatenation
    ... > Your reference to this 'proof', ... Given a pointer to C string one cannot derive the size of array ... Allocation of array to store a string creates _implicit_ context in the ...
    (comp.lang.c)
  • Re: string concatenation
    ... > Your reference to this 'proof', ... Given a pointer to C string one cannot derive the size of array ... Allocation of array to store a string creates _implicit_ context in the ...
    (comp.unix.programmer)
  • Re: C Strings
    ... sizeof ... More generally, given any array object, we can find a pointer to ... works quite as well for C99 as it did for C89, ...
    (comp.lang.c)
  • Wording glitch: sizeof array vs. sizeof (array)
    ... A parenthesized expression is a primary expression. ... Except when it is the operand of the sizeof operator or the unary ... & operator, or is a string literal used to initialize an array, an ...
    (comp.std.c)