Are the literal and constant the same concept in C? - c

Are the literal and constant the same concept in C?
Is there any difference between them in usage?

Literals and constants are significantly different things in C. It can be said that the term literal in C stands for unnamed object that occupies memory (literals are typically lvalues), while the term constant stands for (possibly named) value that does not necessarily occupy memory (constants are rvalues).
"Classic" C (C89/90) had only one kind of literal: string literal. There were no other kinds of literals in that C. C99 additionally introduced so called compound literals.
Meanwhile, the term constant refers to explicit values, like 1, 2.5f, 0xA and 's'. Additionally, enum members are also recognized as constants in C.
Again, since literals in C are lvalues, you can take and use their addresses
const char *s = "Hello";
char (*p)[6] = &"World";
int (*a)[4] = &(int []) { 1, 2, 3, 4 };
Since constants are rvalues, you can't take their addresses.
Objects declared with const keyword are not considered constants in C terminology. They cannot be used where constant values are required (like case labels, bit-field widths or global,static variable initialization).
P.S. Note that the relevant terminology in C is quite different from that of C++. In C++ the term literal actually covers most of what is known in C as constants. And in C++ const objects can form constant expressions. People are sometimes trying to impose C++ terminology onto C, which often leads to confusion.
(See also Shall I prefer constants over defines?)

The C standard (specifically ISO/IEC 9899, Second edition, 1999-12-01) does not define “literal” by itself, so this is not a specific concept for C. I find three uses of “literal”, described below.
First, a string literal (or “string-literal” in the formal grammar) is a sequence of characters inside quotation marks, optionally prefixed with an “L” (which makes it a wide string literal). This is undoubtedly called a literal because each character in the string stands for itself: A ”b” in the source text results in a “b” in the string. (In contrast the characters “34” in the source text as a number, not a string, result in the value 34 in the program, not in the characters “3” and “4”.) The semantics of these literals are defined in paragraphs 4 and 5 of 6.4.5. Essentially, adjacent literals are concatened ("abc" "def" is made into "abcdef"), a zero byte is appended, and the result is used to initialize an array of static storage duration. So a string literal results in an object.
Second, a compound literal is a more complicated construct used to create values for structures. “Compound literal” is an unfortunate name, because it is not a literal at all. That is, the characters in the source text of the literal do not necessarily stand for exactly themselves. In fact, a compound literal is not even a constant. A compound literal can contain expressions that are evaluated at run-time, including function calls!
Third, in 6.1 paragraph 1, the standard indicates that “literal words and character set members” are indicated by bold type. This use of “literal” is describing the standard itself rather than describing things within the C language; it means that “goto” in the standard means the string “goto” in the C language.
Aside from string literals, I do not think “literal” is a particular concept in C.
”Constant”, however, is a significant concept.
First, there are simple constants, such as “34”, “4.5f”, and “'b'”. The latter is a character constant; although written with a character, it has an integer value. Constants include integer constants (in decimal, octal, and hexadecimal), floating constants (in decimal and hexadecimal), character constants, and enumeration constants. Enumeration constants are names specified in “enum” constructs.
Second, there are constant expressions, defined in 6.6. A constant expression can be evaluated during translation (compile time) rather than run time and may be used any place that a constant may be. 6.6 sets certain rules for constant expressions. As an example, if x is a static array, as declared by static int x[8];, then &x[(int) (6.8 * .5)] is a constant expression: It is the address of element 3 of x. (You would rarely using floating-point to index arrays, but I include it in the example to show it is allowed as part of a constant expression.)
Regarding “const”: The standard does not appear to specifically define a const-qualified object as constant. Rather, it says that attempting to modify an object defined with a const-qualified type through an lvalue (such as a dereferenced pointer) with non-const-qualified type, the behavior is undefined. This implies a C implementation is not required to enforce the constantness of const objects. (Also, note that having a pointer-to-const does not imply the pointed-to object is const, just that the dereferenced pointer is not a modifiable lvalue. There could be a separate pointer to the same object that is not const-qualified. For example, in int i; int *p = &i; const int *q = p;, q is a pointer-to-const-int, but i is not a const object, and p is a pointer to the same int although it is pointer-to-int, without const.)

Not quite. Constant variables (as opposed to constants defined in macros) are actual variables with dedicated storage space, so you can take the address of them. You can't take the address of a literal.
Edit: Sorry everyone, it appears that I was mistaken.

Related

Why cannot a const struct field be used as an initializer in C? [duplicate]

I thought C had no more surprises for me, but this surprised me.
const int NUM_FOO = 5;
....
int foo[NUM_FOO];
==>error C2057: expected constant expression
My C++ experience has made me internally deprecate #define as much as possible. So this one was a real surprise. VS2019, compiled with /TC. I thought C99 allowed variable size arrays anyway.
Can anybody explain why the rejection occurs, since the compiler for sure knows at compile time the size of the array?
Is it not the case that C99 allows variable size arrays?
In C, this declaration:
const int NUM_FOO = 5;
doesn't make NUM_FOO a constant expression.
The thing to remember (and yes, this is a bit counterintuitive) is that const doesn't mean constant. A constant expression is, roughly, one that can be evaluated at compile time (like 2+2 or 42). The const type qualifier, even though its name is obviously derived from the English word "constant", really means "read-only".
Consider, for example, that these are a perfectly valid declarations:
const int r = rand();
const time_t now = time(NULL);
The const just means that you can't modify the value of r or now after they've been initialized. Those values clearly cannot be determined until execution time.
(C++ has different rules. It does make NUM_FOO a constant expression, and a later version of the language added constexpr for that purpose. C++ is not C.)
As for variable length arrays, yes, C added them in C99 (and made them optional in C11). But as jamesdlin's answer pointed out, VS2019 doesn't support C99 or C11.
(C++ doesn't support VLAs. This: const int NUM_FOO = 5; int foo[NUM_FOO]; is legal in both C99 and C++, but for different reasons.)
If you want to define a named constant of type int, you can use an enum:
enum { NUM_FOO = 5 };
or an old-fashioned macro (which isn't restricted to type int):
#define NUM_FOO 5
jamesdlin's answer and dbush's answer are both correct. I'm just adding a bit more context.
A variable with the const qualifier does not qualify as a constant expression.
Section 6.6p6 of the C11 standard regarding Constant Expressions states
An integer constant expression shall have integer type and
shall only have operands that are integer constants,
enumeration constants, character constants, sizeof expressions
whose results are integer constants, _Alignof expressions, and
floating constants that are the immediate operands of casts. Cast
operators in an integer constant expression shall only convert
arithmetic types to integer types, except as part of an
operand to the sizeof or _Alignof operator
Note that const qualified integer objects are not included.
This means that int foo[NUM_FOO]; is a variable length array, defined as follows from section 6.7.6.2p4:
If the size is not present, the array type is an incomplete type. If
the size is * instead of being an expression, the array type
is a variable length array type of unspecified size, which can
only be used in declarations or type names with function prototype
scope; such arrays are nonetheless complete types. If the size is
an integer constant expression and the element type has a known
constant size, the array type is not a variable length array
type; otherwise, the array type is a variable length array
type.
As for the error you're getting, that is because Visual Studio is not fully compliant with C99 and does not support variable length arrays.
const in C does not declare a compile-time constant. You can use an enum constant instead if you want to avoid using #define and want a symbolic name that can appear in a debugger.
C99 does support VLAs. However, VS2019 does not support C99.
On top of the existing answers which are all good, the reason a const-qualified object fundamentally can't in general be a constant expression, in the sense of "one that can be evaluated at compile time" (as mentioned in Keith's answer), is that it can have external linkage. For example, you can have in foo.c
const int NUM_FOO = 5;
and in bar.c:
extern int NUM_FOO;
...
int foo[NUM_FOO];
In this example, the value of NUM_FOO cannot be known when compiling bar.c; it is not known until you choose to link foo.o and bar.o.
C's model of "constant expression" is closely tied to properties that allow translation units (source files) to be translated (compiled) independently to a form that requires no further high-level transformations to link. This is also why you can't use addresses in constant expressions except for address constant expressions which are limited to essentially the address of an object plus a constant.

Why is const int x = 5; not a constant expression in C?

I thought C had no more surprises for me, but this surprised me.
const int NUM_FOO = 5;
....
int foo[NUM_FOO];
==>error C2057: expected constant expression
My C++ experience has made me internally deprecate #define as much as possible. So this one was a real surprise. VS2019, compiled with /TC. I thought C99 allowed variable size arrays anyway.
Can anybody explain why the rejection occurs, since the compiler for sure knows at compile time the size of the array?
Is it not the case that C99 allows variable size arrays?
In C, this declaration:
const int NUM_FOO = 5;
doesn't make NUM_FOO a constant expression.
The thing to remember (and yes, this is a bit counterintuitive) is that const doesn't mean constant. A constant expression is, roughly, one that can be evaluated at compile time (like 2+2 or 42). The const type qualifier, even though its name is obviously derived from the English word "constant", really means "read-only".
Consider, for example, that these are a perfectly valid declarations:
const int r = rand();
const time_t now = time(NULL);
The const just means that you can't modify the value of r or now after they've been initialized. Those values clearly cannot be determined until execution time.
(C++ has different rules. It does make NUM_FOO a constant expression, and a later version of the language added constexpr for that purpose. C++ is not C.)
As for variable length arrays, yes, C added them in C99 (and made them optional in C11). But as jamesdlin's answer pointed out, VS2019 doesn't support C99 or C11.
(C++ doesn't support VLAs. This: const int NUM_FOO = 5; int foo[NUM_FOO]; is legal in both C99 and C++, but for different reasons.)
If you want to define a named constant of type int, you can use an enum:
enum { NUM_FOO = 5 };
or an old-fashioned macro (which isn't restricted to type int):
#define NUM_FOO 5
jamesdlin's answer and dbush's answer are both correct. I'm just adding a bit more context.
A variable with the const qualifier does not qualify as a constant expression.
Section 6.6p6 of the C11 standard regarding Constant Expressions states
An integer constant expression shall have integer type and
shall only have operands that are integer constants,
enumeration constants, character constants, sizeof expressions
whose results are integer constants, _Alignof expressions, and
floating constants that are the immediate operands of casts. Cast
operators in an integer constant expression shall only convert
arithmetic types to integer types, except as part of an
operand to the sizeof or _Alignof operator
Note that const qualified integer objects are not included.
This means that int foo[NUM_FOO]; is a variable length array, defined as follows from section 6.7.6.2p4:
If the size is not present, the array type is an incomplete type. If
the size is * instead of being an expression, the array type
is a variable length array type of unspecified size, which can
only be used in declarations or type names with function prototype
scope; such arrays are nonetheless complete types. If the size is
an integer constant expression and the element type has a known
constant size, the array type is not a variable length array
type; otherwise, the array type is a variable length array
type.
As for the error you're getting, that is because Visual Studio is not fully compliant with C99 and does not support variable length arrays.
const in C does not declare a compile-time constant. You can use an enum constant instead if you want to avoid using #define and want a symbolic name that can appear in a debugger.
C99 does support VLAs. However, VS2019 does not support C99.
On top of the existing answers which are all good, the reason a const-qualified object fundamentally can't in general be a constant expression, in the sense of "one that can be evaluated at compile time" (as mentioned in Keith's answer), is that it can have external linkage. For example, you can have in foo.c
const int NUM_FOO = 5;
and in bar.c:
extern int NUM_FOO;
...
int foo[NUM_FOO];
In this example, the value of NUM_FOO cannot be known when compiling bar.c; it is not known until you choose to link foo.o and bar.o.
C's model of "constant expression" is closely tied to properties that allow translation units (source files) to be translated (compiled) independently to a form that requires no further high-level transformations to link. This is also why you can't use addresses in constant expressions except for address constant expressions which are limited to essentially the address of an object plus a constant.

Result of comparing hardcoded strings with ==

The following C code attempts to compare hardcoded strings using ==:
#include <stdbool.h>
bool test_address_aliasing() {
const char * a = "1";
const char * b = "1";
return a==b;
}
This will compare pointers to a and b, and an optimizing compiler will most likely combine the references to a and b to store them in the same place, thus resulting in a==b being true. However, a compiler is not required to combine references to equivalent strings, so is the actual result implementation defined? (I am most interested in C99 if the answer depends on the version of the C spec.)
It is unspecified whether or not two string constants with the same content point to the same object. Section 6.4.5p7 of the C11 standard regarding string constants states:
It is unspecified whether these arrays are distinct provided
their elements have the appropriate values. If the program
attempts to modify such an array, the behavior is undefined.
The actual pointer comparison is valid in either case (see C11 6.5.9p6):
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, both are pointers to
one past the last element of the same array object, or one is a
pointer to one past the end of one array object and the other is a
pointer to the start of a different array object that happens to
immediately follow the first array object in the address
space.
From C standard, 6.4.5 "String literals", item 6:
It is unspecified whether these [string literals] arrays are distinct provided their
elements have the appropriate values.
That means, result of this comparison is unspecified.
Since the question specifically sought advice on C99 (not C17), relevant quotes from the 1999 C standard follow;
Section 6.4.5 "String Literals", para 6 says
It is unspecified whether these arrays are distinct provided their elements have the
appropriate values. If the program attempts to modify such an array, the behavior is
undefined.
Section 6.5.2.5 "Compound literals", para 8.
String literals, and compound literals with const-qualified types, need not designate
distinct objects.
The above also refers to footnote 82, which (while informative, not normative) says;
This allows implementations to share storage for string literals and constant compound literals with the same or overlapping representations.
Para 14 of the same section also provides an example;
EXAMPLE 6 Like string literals, const-qualified compound literals can be placed into read-only memory and can even be shared. For example,
(const char []){"abc"} == "abc"
might yield 1 if the literals’ storage is shared.
Section J.1 (informative) lists a bunch of things that are unspecified in the standard, of which the 14th in the list is
Whether two string literals result in distinct arrays (6.4.5).
From all of the above, it is unspecified whether two string literals with equivalent content are distinct. Two string literals of the form "abc" are allowed but not required to be at the same address in memory. This also means that the result of a (pointer) comparison would be unspecified.
if you do so:
char *a = "1";
char *b ="1";
and then:
if(a==b){ DO SOMETHING} HERE you are comparing the address of memory, where the two pointers are stored.
To compare the content of the memory where the variables are stored(and so to compare the value of the 2 variables) you have to do so:
if(*a == *b){DO SOMETHING}
I hope you mean that

is a compound literal not a literal?

From C in a Nutshell:
Chapter 3 Literals
In C source code, a literal is a token that denotes a fixed value, which may be an integer, a floating-point number, a character, or a string. A literal’s type is determined by its value and its notation.
The literals discussed here are different from compound literals, which were introduced in the C99 standard.
Compound literals are ordinary modifiable objects, similar to variables. For a full description of compound literals and the special operator
used to create them, see Chapter 5.
So a literal has a fixed value, i.e. its value can't be modified, while a compound literal has modifiable values.
According to that, which one is correct:
a compound literal is not a literal, or
the definition of literal should be extended to include a compound literal which becomes the only one exception to the fixed-value rule?
Thanks.
The C11 standard never defines "literal" on its own. It only speaks of "string literal" and "compound literal" individually.
Tokens such as 0, 0.0, the A in enum { A }, and '\0' are called "constants" collectively, and "integer constants", "floating-point constants", "enumeration constants", and "character constants" respectively.

C const - how is pointer to a const possible if a const is an rvalue (ie. not stored in memory)?

Based on corrections of annotations to the standard.
3.14 An object is either a variable or a constant that resides at a physical memory address.
In C, a constant does not reside in memory, (except for some string literals) and so is not an object.
It makes sense to me that a const will not have an actual memory location (except possibly for string literals) and that it depends on the compiler, which will most likely replace all references to it with the literal value. That being said, how is the following possible?
const int * foo;
This declares a pointer to a const int. However, constants don't have an address, so what does this really mean? You can't have a pointer to a literal value that only exists at compile time.
A const variable is not a constant. A constant is a literal value or an expression composed of literal values, like 3+5/2.4. Such constants indeed don't reside in memory, the compiler inserts the literal at the appropriate places.
In your example, foo is not a constant, it is a const-qualified object:
6.7.3 Type qualifiers
Syntax
1 type-qualifier:
const
restrict
volatile
...
3 The properties associated with qualified types are meaningful only for expressions that
are lvalues.114)
...
114) The implementation may place a const object that is not volatile in a read-only region of
storage. Moreover, the implementation need not allocate storage for such an object if its address is
never used.

Resources