10.7 Literal Constant Types and Formats
A literal constant is used to represent a numerical value in the source code; for example, 123 is a constant. Like any value, a literal constant must have a C type. In addition to a literal constant’s type, the actual value can be specified in one of several formats. The format of integral literal constants specifies their radix. MPLAB XC16 supports the ANSI standard radix specifiers as well as ones which enables binary constants to be specified in C code.
The formats used to specify the radices are given in the following table. The letters used to specify binary or hexadecimal radices are case insensitive, as are the letters used to specify the hexadecimal digits.
Radix | Format | Example |
---|---|---|
binary | 0b number or
0B number | 0b10011010 |
octal |
0 number | 0763 |
decimal | number | 129 |
hexadecimal |
0x number or 0X number | 0x2F |
Any integral literal constant will have a type of int
,
long int
or long long int
, so that the type can hold
the value without overflow. Literal constants specified in octal or hexadecimal may also be
assigned a type of unsigned int
, unsigned long int
or
unsigned long long int
if the signed counterparts are too small to hold
the value.
The default types of literal constants may be changed by the addition of a
suffix after the digits, e.g., 23U
, where U
is the
suffix. The table below shows the possible combination of suffixes, and the types that are
considered when assigning a type. So, for example, if the suffix l
is
specified and the value is a decimal literal constant, the compiler will assign the
type long int
, if that type will hold the lineal constant; otherwise,
it will assign long long int
. If the literal constant was specified as an
octal or hexadecimal constant, then unsigned types are also considered.
Suffix | Decimal | Octal or Hexadecimal |
---|---|---|
u or
U | unsigned int
| unsigned int
|
l or
L | long int
| long int
|
u or U , and
l or L | unsigned long int
| unsigned long int
|
ll or
LL | long long int | long long int unsigned long long int |
u or U , and
ll or LL | unsigned long long
int | unsigned long long
int |
Here is an example of code that may fail because the default type assigned to a literal constant is not appropriate:
unsigned long int result;
unsigned char shifter;
void main(void)
{
shifter = 20;
result = 1 << shifter;
// code that uses result
}
The literal constant 1
will be assigned an
int
type; hence the result of the shift operation will be an
int
and the upper bits of the long
variable,
result
, can never be set, regardless of how much the literal constant
is shifted. In this case, the value 1 shifted left 20 bits will yield the result 0, not
0x100000.
The following uses a suffix to change the type of the literal constant,
hence ensure the shift result has an unsigned long
type.
result = 1UL << shifter;
Floating-point literal constants have double
type unless
suffixed by f
or F
, in which case it is a float constant.
The suffixes l
or L
specify a long
double
type. In MPLAB XC16, the double
type equates to a
32-bit float type. The command line option, -fno-short-double
, may be use
to specify double as a 64-bit long double
type.
Fixed-point literal constants look like floating point numbers, suffixed
with combinations of
[u
][h,l
]<r,k
>. The suffix
u
means unsigned. The suffixes h
and
l
signify short and long respectively. The suffix r
denotes a _Fract
type and k
specifies an
_Accum
type. So for example, -1
.0r is a signed
_Fract
and 0.5uhk
is an unsigned short
_Accum
.
Character literal constants are enclosed by single quote characters,
’
, for example ‘a’
. A character literal constant has
int
type, although this may be optimized to a char
type later in the compilation.
Multi-byte character literal constants are supported by this implementation.
String constants, or string literals, are enclosed by double quote
characters "
, for example "hello world"
. The type of
string literal constants is const char *
and the character that make up
the string may be stored in the program memory.
To comply with the ANSI C standard, the compiler does not support the extended character set in characters or character arrays. Instead, they need to be escaped using the backslash character, as in the following example:
const char name[] = "Bj\xf8k";
printf("%s's Resum\xe9", name); \\ prints "Bjørk's
Resumé"
Defining and initializing a non-const
array (i.e., not a
pointer definition) with a string, for example:
char ca[]= "two"; // "two" different to the above
is a special case and produces an array in data space which is initialized
at startup with the string "two"
, whereas a string literal constant used
in other contexts represents an unnamed array, accessed directly from its storage
location.
The compiler will use the same storage location and label for strings that have identical character sequences, except where the strings are used to initialize an array residing in the data space as shown in the last statement in the previous example.
Two adjacent string literal constants (i.e., two strings separated only by white space) are concatenated by the C preprocessor. Thus:
const char * cp = "hello " "world";
will assign the
pointer with the address of the string "hello world."