According to Draft Standard §6.5.3.2 ¶1, the use of the address operator must be subject to the following restriction:
The operand of the unary operator & must be either the function name, the result of the [] operator or the unary * or lvalue, which indicates an object that is not a bit field and is not declared by the register class specifier.
The value of lvalue is given in §6.3.2.1 ¶1 :
The lvalue value is an expression (with an object type other than void ) that potentially denotes an object.
According to §3.15 ¶1 the object is:
a data storage area in the runtime whose contents can represent values.
Now the constant is not an lvalue value; a constant has a value, but a constant does not indicate an object, and a value cannot be assigned to a constant. Thus, a constant is not a function designation, is not the result of the [] operator or unary * and is not an lvalue value, which means that accessing the constant address is a violation of the restriction. A diagnostic message should be issued using the appropriate implementation.
On the other hand, given const int u = 9; , u is a const qualified variable of type int . This declaration reserves memory for the variable, and u is the value of lvalue. Using const does not mean that u is a constant, but the object indicated by the identifier u is const (this is not the same thing). It might be better to think of const qualified variables as read-only; it is a promise made by the program that the object indicated by u will not be modified. Since u is an lvalue here (it is not a bit field and is not declared with the register keyword), it must accept its address with &u .
Note that the published code has undefined behavior, since the correct printf() conversion specifier for print addresses is %p ; its argument must be distinguished to (void *) . Inappropriate specifications and conversion arguments result in undefined behavior. So the correct code is:
const int u = 9; printf ("\nHello World! %p ", (void *) &u);