int a = 12;
The identifier 'a' is an object of type int, with the value of 12.
The integer literal 12 has the value of 12 but is not an object.
More precisely, the identifier is the name of (or "a label for")
an object of type int. The object itself is the "region of storage":
3.15 Object
[#1] A region of data storage in the execution environment,
the contents of which can represent values. Except for
bit-fields, objects are composed of contiguous sequences of
one or more bytes, the number, order, and encoding of which
are either explicitly specified or implementation-defined.
When referenced, an object may be interpreted as having a
particular type; see 6.2.2.1.
(from a C99 draft).
No constant is an object, and no object is ever a constant, in C
(here C differs markedly from C++, where "const" variables *are*
constants, yet can be C-style objects). Note that I use the
ANSI C definition of the term "constant" here:
constant:
floating-constant
integer-constant
enumeration-constant
character-constant
(same C99 draft, but uchanged from C89). These differ from a
"constant-expression"; for instance, while (1+2) is a
"constant-expression", it is not a "constant".
String literals (except when used as initializers for character
arrays) are a special case: they create objects that have static
duration. The address of *any* static-duration object -- not just
those from string literals -- has a "constant address", which can
be computed at compile and/or link time in most cases, but this
does not make it a "constant", or even a "constant-expression",
in C. You *can* use them as initializers for other static-duration
variables though:
static char *p = "string literal";
or:
static double pi = 2.718281828459045235360287; /* [%] */
static double *dp = π
[% A rather precise pi, but not very accurate.
]
Hence, the concept of "constant" in C is somewhat peculiar and
subtle.
In C89, with one kind-of-broken exception, arrays are never values,
only objects. C99 attemps to correct the problem, which occurs
with struct-valued functions in which the struct contains (or
even consists of) an array:
struct S { int a[20]; };
struct S f(void);
...
... f().a ...
Here f().a appears as a sub-expression, yet because it part of a
returned struct, the array "a" is not an object with automatic,
static, or allocated duration. In effect, it is an array value,
instead of an array object. The problem is that you cannot take
the address of a value in C:
int *p = &42; /* invalid -- diagnostic required */
Array subscripting works, at least conceptually, by taking the
address of the array's first element, so f().a
needs to "take
the address" of f().a -- an address that does not exist. C99's
solution to this problem in C89 wound up re-defining "lvalue" badly.
(I am not sure that there *is* any good solution to this. The
approach I would probably have taken is to define all structure-valued
functions as returning an "automatically-dereferenced pointer" to
a "very-short-duration object", but describing the storage duration
of that object is itself problematic. This pointer would allow
computing &(f().a), and even &(f()), and using it until the object's
duration expires. Depending on the lifetime, passing &(f()) to
memcpy() might become valid, for instance. I suspect the right
duration might be "until the next sequence point", though, and the
sequence point before the call to memcpy() would invalidate the
pointer. But then consider calls of the form: g(f(), f()), where
g() is a function taking a "struct S" -- are they defined, or not?)