This is one of the rationales behind the general guideline on using a single int type only conversion to than the maximum value that can be represented in the new type until the value is
Trang 1Why would a vendor provide an extended type that is the same width as one of the standard integer types?
The translator vendor may support a variety of different platforms and want to offer a common set of typedefs,
across all supported platforms, in the<stdint.h>header This could have the effect, on some platforms,
of an extended integer type having the same width as one of the standard integer types A vendor may also
provide more than one representation of integer types For instance, by providing support for extended
integer types whose bytes have the opposite endianness to that of the standard integer types 570 endian
This does not imply that the object representation of the type_Boolcontains a smaller number of bits than
any other integer type (although its value representation must)
593 unsigned integer types object representa- tion
The C++Standard places no requirement on the relative size of the typeboolwith respect to the other integer
types An implementation may choose to hold the two possible values in a single byte, or it may hold those
values in an object that has the same width as typelong
Other Languages
Boolean types, if supported, are usually viewed as the smallest type, irrespective of the amount of storage
used to represent them
Most languages that contain enumerated types treat them as being distinct from the integer types and an
explicit cast is required to obtain their numeric value So the C issues associated with rank do not occur
extended teger relative
in-to extended
same precision is implementation-defined, but still subject to the other rules for determining the integer
conversion rank
Trang 2The reasons why an implementation might provide two extended signed integer types of the same precision
is the same as the reasons why it might provide such a type having the same precision as a standard integertype Existing practice provides a ranking for the standard integer types (some or all of which may have the
motions
675
integer type can be used in an expression wherever anintorunsigned intmay be used (this may involvethem being implicitly converted) However, operands having one of the types specified in the followingsentences will often return the same result if they also have the typeintorunsigned int
C90
The C90 Standard listed the types, while the C99 Standard bases the specification on the concept of rank
Achar, ashort int, or anintbit-field, or their signed or unsigned varieties, or an enumeration type, may be
C++
C++supports the overloading of operators; for instance, a developer-defined definition can be given to thebinary+operator, when applied to operands having typeshort Given this functionality, this C sentencecannot be said to universally apply to programs written in C++ It is not listed as a difference because itrequires use of C++functionality for it to be applicable The implicit conversion sequences are specified
in clause 13.3.3.1 When there are no overloaded operators visible (or to be exact no overloaded operatorstaking arithmetic operands, and no user-defined conversion involving arithmetic types), the behavior is thesame as C
Other Languages
Most other languages do not define integer types that have less precision than typeint, so they do not contain
an equivalent statement The typecharis usually a separate type and an explicit conversion is needed if anoperand of this type is required in anintcontext
Trang 3the firstreturnstatement will always return zero when the rank of typeTis less than or equal to the rank of
int There is no guarantee that the secondreturnstatement will always deliver the same value for different
types
Commentary
The rank ofintandunsigned intis the same The integer promotions will be applied to these objects 663rankcorresponding
signed/unsigned
675 integer motionsThe wording was changed by the response to DR #230 and allows objects having enumeration type (whose
pro-rank may equal the pro-rank ofintandunsigned int) to appear in these contexts (as did C90)
C++
4.5p1
4.5p2
long
4.5p4
one
The key phrase here is can be, which does not imply that they shall be However, the situations where these
conversions might not apply (e.g., operator overloading) do not involve constructs that are available in C For
binary operators the can be conversions quoted above become shall be requirements on the implementation
(thus operands with rank less than the rank ofintare supported in this context):
5p9
Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield
result types in a similar way The purpose is to yield a common type, which is also the type of the result This
pattern is called the usual arithmetic conversions, which are defined as follows:
Footnote 54
Trang 454) As a consequence, operands of typebool,wchar_t, or an enumerated type are converted to some integraltype.
The C++Standard does not appear to contain explicit wording giving this permission for other occurrences ofoperands (e.g., to unary operators) However, it does not contain wording prohibiting the usage (the wordingfor the unary operators invariably requires the operand to have an arithmetic or scalar type)
signed int
C90
Support for bit-fields of type_Boolis new in C99
C++
4.5p3 An rvalue for an integral bit-field (9.6) can be converted to an rvalue of typeintifintcan represent all the
values of the bit-field If the bit-field is larger yet, no integral promotion applies to it If the bit-field has anenumerated type, it is treated as any other value of that type for promotion purposes
C does not support the definition of bit-fields that are larger than typeint, or bit-fields having an enumeratedtype
Other Languages
Languages, such as Pascal and Ada, provide developers with the ability to specify the minimum andmaximum values that need to be represented in an integer type (a bit-field specifies the number of bits in therepresentation, not the range of values) These languages contain rules that specify how objects defined tohave these subrange types can be used anywhere that an object having integer type can appear
Common Implementations
Obtaining the value of a member that is a bit-field usually involves several instructions The storage unitholding the bit-field has to be loaded, invariably into a register Those bits not associated with the bit-fieldbeing read then need to be removed This can involve using a bitwise-and instruction to zero out bits and rightshift the bit sequence For signed bit-fields, it may then be necessary to sign extend the bit sequence Storing
a value into an object having a bit-field type can be even more complex The new value has to be converted
to a bit sequence that fits in the allocate storage, without changing the values of any adjacent objects
Some CISC processors[985] have instructions designed to access bit-fields Such relatively complexinstructions went out of fashion when RISC design philosophy first took off, but they have started to make acome back.[6, 641]Li and Gupta[863]found that adding instructions to the ARM processor that operated (add,subtract, compare, move, and bitwise operations) on subwords reduced the cycle count of various multimediabenchmarks by between 0.39% and 8.67% (code size reductions were between 1.27% and 21.05%)
Trang 5673If anintcan represent all values of the original type, the value is converted to anint; int can
repre-sent values converted to int
Commentary
Type conversions occur at translation time, when actual values are usually unknown The standard requires
the translator to assume that the value of the expression can be any one of the representable values supported
by its type While flow analysis could reduce the range of possible values, the standard does not require such
analysis to be performed (If it is performed, a translator cannot use it to change the external behavior of a
program; that is, optimizations may be performed but the semantics specified by the standard is followed.)
promotions Incorrect assumptions by a developer are very difficult to deduce from an analysis of the source
code In some cases the misconception will be harmless, the actual program behavior being identical to
the misconstrued behavior In other cases the behavior is different Guideline recommendations are not a
substitute for proper developer training
Commentary
This can occur for the typesunsigned short, orunsigned char, if either of them has the same
represen-tation as anunsigned int Depending on the type chosen to be compatible with an enumeration type, it is
possible for an object that has an enumerated type to be promoted to the typeunsigned int
Common Implementations
On 16-bit processors the typesshortandintusually have the same representation, sounsigned short
promotes tounsigned int On 32-bit processors the typeshortusually has less precision thanint, so the
typeunsigned shortpromotes toint There are a few implementations, mostly on DSP-based processors,
where the character types have the same width as the typeint.[984]
Coding Guidelines
Existing source code ported, from an environment in which the typeinthas greater width thanshort, to
an environment where they both have the same width may have its behavior changed If the following is
executed on a host where the width of typeintis greater than the width ofshort:
Trang 61 #include <stdio.h>
2
3 extern unsigned short us;
4 extern signed int si; /* Can hold negative values */
application of the integer promotions
The consequence of this guideline recommendation is that such conversions need to be made explicit, using acast to an integer type whose rank is greater than or equal toint
This defines the term integer promotions Integer promotions occur when an object having a rank less than
intappears in certain contexts This behavior differs from arithmetic conversions where the type of afootnote
48690
different object is involved Integer promotions are affected by the relative widths of types (compared to thewidth ofint) If the typeinthas greater width thanshortthen, in general (the presence of extended integertypes whose rank is also less thanintcan complicate the situation), all types of less rank will convert toint
Ifshorthas the same precision asint, anunsigned shortwill invariably promote to anunsigned int
It is possible to design implementations where the integer conversions don’t follow a simple pattern, such
as the following:
signed short 16 bits including sign unsigned short 24 bits
Your author does not know of any implementation that uses this kind of unusual combination of bits forits integer type representation
Trang 7Common Implementations
Many processors have load instructions that convert values having narrower types to a wider type For
instance, loading a byte into a register and either sign extending (signed char), or zero filling (unsigned
char) the value to occupy 32 bits (promotion toint) On processors having instructions that operate on
values having a type narrower thanintmore efficiently than typeint, optimizers can make use of the as-if
rule to improve efficiency For instance, in some cases an analysis of the behavior of a program may find that
operand values and the result value is always representable in their unpromoted type Implementations need
only to act as if the object had been converted to the typeint, orunsigned int
Coding Guidelines
If the guideline recommendation specifying use of a single integer type is followed there would never be any480.1 object
int type only
integer promotions The issue of implicit conversions versus explicit conversions might be a possible cause
of a deviation from this recommendation and is discussed elsewhere 653operandconvert
7 * The result of + may be undefined.
8 * The conversion for the = may be undefined.
10 /* s1 = (short)((int)s2 + (int)s3); */
11 s1 = us2 + s3; /* The conversion for the = may be undefined */
13 * The result of the binary + is always defined (unless
14 * the type int is only one bit wider than a short; no
15 * known implementations have this property).
25 s1 = us2 + us3; /* The conversion for the = may be undefined */
26 us1 = us2 + us3; /* Always defined */
27 us1 = us2 + s3; /* Always defined */
28 us1 = s2 + s3; /* The result of + may undefined */
29 }
Table 675.1: Occurrence of integer promotions (as a percentage of all operands appearing in all expressions) Based on the
translated form of this book’s benchmark programs.
Trang 8in many cases this promoted value appears as an operand of a binary operator If unsigned preservingpromotionswere used (see Common implementations below), the value of the operand could have its signchanged (e.g., if the operands had typesunsigned charandsigned char, both their final operand typewould have beenunsigned int), potentially leading to a change of that value (if it was negative) Theunsigned preserving promotions(sometimes called rules rather than promotions) are sometimes also known
as sign preserving rules because the form of the sign is preserved
Most developers think in terms of values, not signedness A rule that attempts to preserve sign can cause achange of value, something that is likely to be unexpected Value preserving rules can also produce resultsthat are unexpected, but these occur much less often
RationaleThe unsigned preserving rules greatly increase the number of situations whereunsigned intconfrontssigned
Thus, the value preserving rules were considered to be safer for the novice, or unwary, programmer Aftermuch discussion, the C89 Committee decided in favor of value preserving rules, despite the fact that the UNIX
C compilers had evolved in the direction of unsigned preserving
Trang 95 int si = -1;
6 /*
7 * Value preserving rules promote uc to an int -> comparison succeeds.
9 * Signed preserving rules promote uc to an unsigned int, usual arithmetic
10 * conversions then convert si to unsigned int -> comparison fails.
any of the character types can represent the same range of values as an object of typeintorunsigned int
6.3.1.2 Boolean type
converted to
Commentary
Converting a scalar value to type_Boolis effectively the same as a comparison against0; that is,(_Bool)x
is effectively the same as(x != 0)except in the latter case the type of the result isint
Conversion to_Boolis different from other conversions, appearing in a strictly conforming program, in
that it is not commutative—(T1)(_Bool)xneed not equal(_Bool)(T1)x For instance:
(int)(_Bool)0.5 ⇒ 1 (_Bool)(int)0.5 ⇒ 0
Reordering the conversions in a conforming program could also return different results:
(signed)(unsigned)-1 ⇒ implementation-defined (unsigned)(signed)-1 ⇒ UINT_MAX
C90
Support for the type_Boolis new in C99
C++
4.12p1
An rvalue of arithmetic, enumeration, pointer, or pointer to member type can be converted to an rvalue of type
The value offalseis not defined by the C++Standard (unliketrue, it is unlikely to be represented using
any value other than zero) But in contexts where the integer conversions are applied:
4.7p4
Other Languages
Many languages that include a boolean type specify that it can hold the values true and false, without
specifying any representation for those values Java only allows boolean types to be converted to boolean
types It does not support the conversion of any other type to boolean
Trang 10Coding Guidelines
The issue of treating boolean values as having a well-defined role independent of any numeric value isdiscussed elsewhere; for instance, treating conversions of values to the type_Boolas representing a changeboolean role 476
of role, not as representing the values 0 and 1 The issue of whether casting a value to the type_Bool, ratherthan comparing it against zero, represents an idiom that will be recognizable to C developers is discussedelsewhere
4.12p1 ; any other value is converted totrue
The value oftrueis not defined by the C++Standard (implementations may choose to represent it internallyusing any nonzero value) But in contexts where the integer conversions are applied:
4.7p4 the valuetrueis converted to one
6.3.1.3 Signed and unsigned integers
682
represented by the new type, it is unchanged
Commentary
While it would very surprising to developers if the value was changed, the standard needs to be complete andspecify the behavior of all conversions For integer types this means that the value has to be within the rangespecified by the corresponding numerical limits macros
numeri-cal limits300
The type of a bit-field is more than just the integer type used in its declaration The width is also considered
to be part of its type This means that assignment, for instance, to a bit-field object may result in the valuebit-field
7 * The value 3 can be represented in an unsigned int,
8 * but is changed by the assignment in this case.
Trang 11Common Implementations
The value being in range is not usually relevant because most implementations do not perform any range
checks on the value being converted When converting to a type of lesser rank, the common implementation
behavior is to ignore any bit values that are not significant in the destination type (The sequence of bits in
the value representation of the original type is truncated to the number of bits in the value representation
of the destination type.) If the representation of a value does not have any bits set in these ignored bits, the
converted value will be the same as the original value In the case of conversions to value representations
containing more bits, implementations simply sign-extend for signed values and zero-fill for unsigned values
Coding Guidelines
One way of reducing the possibility that converted values are not representable in the converted type is to
reduce the number of conversions This is one of the rationales behind the general guideline on using a single
int type only
conversion to
than the maximum value that can be represented in the new type until the value is in the range of the new
Commentary
This behavior is what all known implementations do for operations on values having unsigned types The
standard is enshrining existing processor implementation practices in the language As footnote 49 points 691 footnote
49
out, this adding and subtracting is done on the abstract mathematical value, not on a value with a given C
type There is no need to think in terms of values wrapping (although this is a common way developers think
about the process)
C90
Otherwise: if the unsigned integer has greater size, the signed integer is first promoted to the signed integer
corresponding to the unsigned integer; the value is converted to unsigned by adding to it one greater than the
When a value with integral type is demoted to an unsigned integer with smaller size, the result is the nonnegative
remainder on division by the number one greater than the largest unsigned number that can be represented in the
type with smaller size
The C99 wording is a simpler way of specifying the C90 behavior
Common Implementations
For unsigned values and signed values represented using two’s complement, the above algorithm can be
implemented by simply chopping off the significant bits that are not available in the representation of the
new type
Coding Guidelines
The behavior for this conversion may be fully specified by the standard The question is whether a conversion
To be exact, the standard defines no algorithm for reducing the value to make it representable (because there
is no universal agreement between different processors on what to do in this case)
Other Languages
The problem of what to do with a value that, when converted to a signed integer type, cannot be represented
is universal to all languages supporting more than one signed integer type, or support an unsigned integer
type (the overflow that can occur during an arithmetic operation is a different case)
Trang 124.7p3 ; otherwise, the value is implementation-defined
The C++Standard follows the wording in C90 and does not explicitly permit a signal from being raised inthis context because this behavior is considered to be within the permissible range of implementation-definedbehaviors
as a sign bit, which is sign-extended to fill the available space if the value is being held in a register If theconversion occurs immediately before a store (i.e., a right-hand side value is converted before being assignedinto the left hand side object), there is often no conversion; the appropriate number of value bits are simplywritten into storage
Some older processors[287]have the ability to raise a signal if a conversion operation on an integer value isnot representable On such processors an implementation can choose to use this instruction or use a sequence
of instructions having the same effect, that do not raise a signal
6.3.1.4 Real floating and integer
Trang 13The Sign Bit and the sign of the result of the round floating-point number to integer operation is the sign of
the operand These rules shall apply even when operands or results are zero or infinite
When a floating-point value in the range (-1.0, -0.0) is converted to an integer type, the result is required to
Many processors include instructions that perform truncation when converting values of floating type to
an integer type On some processors the rounding mode, which is usually set to round-to-nearest, has to 352
FLT_ROUNDS
be changed to round-to-zero for this conversion, and then changed back after the operation This is an
execution-time overhead Some implementations give developers the choice of faster execution provided
they are willing to accept round-to-nearest behavior In some applications the difference in behavior is
significantly less than the error in the calculation, so it is acceptable
Coding Guidelines
An expression consisting of a cast of a floating constant to an integer type is an integer constant expression.1328integer con-stant
expres-sionSuch a constant can be evaluated at translation time However, there is no requirement that the translation-time
evaluation produce exactly the same results as the execution-time evaluation Neither is there a requirement
that the translation-time handling of floating-point constants be identical In the following example it is
possible that a call toprintfwill occur
There is a common, incorrect, developer assumption that floating constants whose fractional part is zero
are always represented exactly by implementations (i.e., many developers have a mental model that such
constants are really integers with the characters.0appended to them) While it is technically possible to
convert many such constants exactly, experience shows that a surprising number of translators fail to achieve
the required degree of accuracy (e.g., the floating constant 6.0 might be translated to the same internal
representation as the floating constant 5.999999 and subsequently converted to the integer constant 5)
A program shall not depend on the value of a floating constant being converted to an integer constant
having the same value
A developer who has made the effort of typing a floating constant is probably expecting it to be used as a
floating type Based on this assumption a floating constant that is implicitly converted to an integer type is
unexpected behavior Such an implicit conversion can occur if the floating constant is the right operand of an
assignment or the argument in a function call Not only is the implicit conversion likely to be unexpected by
the original author, but subsequent changes to the code that cause a function-like macro to be invoked, rather
than a function call, to result in a significant change in behavior
Trang 14In the following example, a floating constant passed toCALC_1results inglobbeing converted to a floatingtype If the value ofglobcontains more significant digits than supported by the floating type, the final resultassigned tolocwill not be the value expected Using explicit casts, as inCALC_2, removes the problemcaused by the macro argument having a floating type However, as discussed elsewhere, other dependenciesoperand
4 #define CALC_1(a) ((a) + (glob))
5 #define CALC_2(a) ((long)(a) + (glob))
6 #define CALC_3(a) ((a) + (glob)) 7
8 extern long glob;
The previous discussion describes some of the unexpected behaviors that can occur when a floating constant
is implicitly converted to an integer type Some of the points raised also apply to objects having a floatingtype The costs and benefits of relying on implicit conversions or using explicit casts are discussed, in general,elsewhere That discussion did not reach a conclusion that resulted in a guideline recommendation beingoperand
Other Languages
Other languages vary in their definition of behavior Like integer values that are not representable in thedestination type, some languages require an exception to be raise while others specify undefined behavior Inthis case Java uses a two step-process It first converts the real value to the most negative, or largest positive
Trang 15(depending on the sign of the floating-point number) value representable in alongor anint In the second
step, if the converted integer type is notlongorint; the narrowing conversions are applied to the result of
the first step
Common Implementations
Many processors have the option of raising an exception when the value cannot be represented in the integer
type Some allow these exceptions to be switched off, returning the least significant bytes of the value The
IEC 60559 Standard defines the behavior— raise invalid Most current C99 implementations do not do this
In graphics applications saturated arithmetic is often required (see Figure687.1) Some DSP proces- arithmetic
saturatedsors[984]and the Intel MMX instructions[637]return the largest representable value (with the appropriate
sign)
Coding Guidelines
A naive analysis would suggest there is a high probability that an object having a floating type will hold a
value that cannot be represented in an integer type However, in many programs the range of floating-point
values actually used is relatively small It is this application-specific knowledge that needs to be taken into334 exponentaccount by developers
Those translators that perform some kind of flow analysis on object values often limit themselves to
tracking the values of integer and pointer types Because of the potential graininess in the values they
represent and their less common usage, objects having floating types may have their set/unset status tracked
but their possible numeric value is rarely tracked
It might appear that, in many ways, this case is the same as that for integer conversions where the value
cannot be represented However, a major difference is processor behavior There is greater execution 684integer valuenot represented in
signed integer
overhead required for translators to handle this case independently of how the existing instructions behave
Also, a larger number of processors are capable of raising an exception in this case
Given that instances of this undefined behavior are relatively rare and instances might be considered to be
a fault, no guideline recommendation is made here
conversion
to floating
exactly in the new type, it is unchanged
Commentary
The value may be unchanged, but its representation is likely to be completely changed
There are the same number of representable floating-point values between every power of two (when
FLT_RADIXhas a value of two, the most common case) As the power of two increases, the numeric distance366 FLT_RADIXbetween representable values increases (see Figure368.1) The value of the*_DIGmacros specify the369 *_DIG
macros
number of digits in a decimal value that may be rounded into a floating-point number and back again without
change of value In the case of the single-precision IEC 60559 representationFLT_DIGis six, which is less
than the number of representable digits in an object having typelong(or 32-bitint)
Figure 687.1: Illustration of the effect of integer addition wrapping rather than saturating A value has been added to all of the
pixels in the left image to increase the brightness, creating the image on the right With permission from Jordán and Lotufo.[703]
Trang 164.9p2 An rvalue of an integer type or of an enumeration type can be converted to an rvalue of a floating point type The
result is exact if possible
Who decides what is possible or if it can be represented exactly? A friendly reading suggests that the meaning
The major conceptual difference between integer and floating types is that one is expected to hold anexact value and the other an approximate value If developers are aware that approximations can begin atthe point an integer value is converted, then it is possible for them to take this into account in designingalgorithms Developers who assume that inaccuracies don’t occur until the floating value is operated on are
in for a surprise
Algorithms containing integer values that are converted to floating values shall be checked to ensurethat any dependence on the accuracy of the conversion is documented and that any necessary
The rationale behind the guideline recommendations against converting floating constants to integer constantsfloating
4 static float max_short = (float)SHRT_MAX;
5 static float max_int = (float)INT_MAX;
6 static float max_long = (float)LONG_MAX;
Trang 17repre-the result is eirepre-ther repre-the nearest higher or nearest lower representable value, chosen in an
Coding Guidelines
A consequence of this behavior is that it is possible for two unequal integer values to be converted to the
same floating-point value Any algorithm that depends on the relationships between integer values being
maintained after conversion to a floating type may not work as expected
48
as specified by their respective subclauses
Commentary
The certain argument expressions are function calls where there is no type information available This
happens for old-style function declarations and for prototype declarations where the ellipsis notation has
been used and the argument corresponds to one of the parameters covered by this notation
Another context where integer promotions are applied is the controlling expression in aswitchstatement
In all other cases the operand is being used in a context where its value is being operated on
Contexts where the integer promotions are not applied are the expression specifying the number of
elements in a VLA type definition (when there are no arithmetic or logical operators involved), function
return values, the operands of the assignment operator, and arguments to a function where the parameter type
is known In the latter three cases the value is, potentially, implicitly cast directly to the destination type
The standard does not specify that the implicit test against zero, in anifstatement or iteration statement,1744if statementoperand compare
against 0
1766 iteration statement executed repeat- edly
will cause a single object (forming the complete controlling expression) to be promoted A promotion would
not affect the outcome in these contexts, and an implementation can use the as-if rule in selecting the best
machine code to generate
C++
In C++, integral promotions are applied also as part of the usual arithmetic conversions, the operands of the
unary+,-, and~operators, and to both operands of the shift operators C++also performs integer promotions
in contexts not mentioned here, as does C
Trang 18Coding Guidelines
There are a small number of cases where the integer promotions do not occur Is anything to be gained
by calling out these situations in coding guideline documents? Experience suggests that developers aremore likely to forget that the integer promotions occur (or invent mythical special cases where they don’toccur) rather than worry about additional conversions because of them Coding guideline documents are nosubstitute for proper training
C++
4.9p1 An rvalue of a floating point type can be converted to an rvalue of an integer type The conversion truncates; that
is, the fractional part is discarded The behavior is undefined if the truncated value cannot be represented in thedestination type
The conversion behavior, when the result cannot be represented in the destination type is undefined in C++
and unspecified in C
Common Implementations
The floating-point to integer conversion instructions on many processors are only capable of delivering signedinteger results An implementation may treat the value as a sequence of bits independent of whether a signed
or unsigned value is expected In this case the external behavior for two’s complement notation is the same as
if a remaindering operation had been performed Converting values outside of the representable range of anyinteger type supported by an implementation requires that the processor conversion instruction either performthe remainder operation or raise some kind of range error signal that is caught by the implementation, whichthen performs the remainder operation in software
Trang 19The round brackets are being used in the mathematical sense; the bounds represent excluded limits (i.e., -1 is
not in the portable range) This statement only applies to unsigned integer types
C++
The C++Standard does not make this observation
Commentary
An unsigned integer type represented in 123 bits, or more, could contain a value that would be outside the
range of values representable in a minimum requirementsfloattype (128 bits would be needed to exceed 373
*_MAX_10_EXPthe range of the IEC 60559 single-precision)
C++
4.9p2
Otherwise, it is an implementation-defined choice of either the next lower or higher representable value
The conversion behavior, when the result is outside the range of values that can be represented in the
destination type, is implementation-defined in C++and undefined in C
Other Languages
Many other language standards were written in an age when floating-point types could always represent
much larger values than could be represented in integer types and their specifications reflect this fact (by not
mentioning this case) In Java values having integer type are always within the representable range of the
floating-point types it defines
Common Implementations
Processors that support 128-bit integer types, in hardware, are starting to appear.[29]
Coding Guidelines
Developers are likely to consider this issue to be similar to the year 2036 problem— address the issue when
the course of history requires it to be addressed
6.3.1.5 Real floating types
promoted to ble or long double
dou-unchanged (if the source value is represented in the precision and range of its type)
Trang 20Although not worded as such, this is a requirement on the implementation The typedoublemust have atleast the same precision in the significand and at least as much range in the exponent as the typefloat,similarly for the typesdoubleandlong double
A situation where the source value might not be represented in the precision and range of its type is when
FLT_EVAL_METHODhas a non-zero value For instance, ifFLT_EVAL_METHODhas a value of 2, then the valueFLT_EVAL_METHOD354
0.1fis represented to the precision oflong double, while the type remains asfloat If a cast todouble
is performed<footnote, 87> the value may be different to that obtained whenFLT_EVAL_METHODwas zero.The wording was changed by the response to DR #318
C++
3.9.1p8 The typedoubleprovides at least as much precision asfloat, and the typelong doubleprovides at least as
This only gives a relative ordering on the available precision It does not say anything about promotionleaving a value unchanged
4.6p1 An rvalue of typefloatcan be converted to an rvalue of typedouble The value is unchanged
There is no equivalent statement for type doubletolong doublepromotions But there is a generalstatement about conversion of floating-point values:
4.8p1 An rvalue of floating point type can be converted to an rvalue of another floating point type If the source value
can be exactly represented in the destination type, the result of the conversion is that exact representation
Given that (1) the set of values representable in a floating-point type is a subset of those supported by a widerfloating-point type (3.9.1p8); and (2) when a value is converted to the wider type, the exact representation isrequired to be used (by 4.8p1)— the value must be unchanged
Other Languages
Some languages specify one floating type, while others recognize that processors often support severaldifferent floating-point precisions and define mechanisms to allow developers to specify different floatingtypes While implementations that provide multiple floating-point types usually make use of the sameprocessor hardware as that available to a C translator, other languages rarely contain this requirement
Commentary
A simple calculation would suggest that unless an implementation uses the same representation for point types, the statistically likelihood of a demoted value being exactly representable in the new typewould be very low (an IEC 60559 double-precision type contains 232 values that convert to the samesingle-precision value) However, measurements of floating-point values created during program executionshow a surprisingly high percentage of value reuse (these results are discussed elsewhere)
floating-binary *
result
1147
value
profiling940 A situation where a value might be represented in greater precision and range than required by its type is
whenFLT_EVAL_METHODhas a non-zero value
FLT_EVAL_METHOD354
float
promoted to dou-695
Trang 21The wording was changed by the response to DR #318.
C90
This case is not specified in the C90 Standard
Coding Guidelines
Relying on the converted value being equal to the original value is simply a special case of comparing two
floating-point values for equality
1214.1 equality operators not floating-point operands
Why is a floating-point value being demoted? If a developer is concerned about a floating-point value
being represented to a greater precision than required by its semantic type, explicit conversions might be 354
FLT_EVAL_METHODused simply as a way of ensuring known behavior in the steps in a calculation Or perhaps a computed value
is being assigned to an object There are sometimes advantages to carrying out the intermediate steps in an
expression evaluation in greater precision than the result that will be saved 64correctlyrounded
result
the result is either the nearest higher or nearest lower representable value, chosen in an
implementation-defined manner
Commentary
AlthoughFLT_ROUNDSis only defined to characterize floating-point addition, its value is very likely to352
FLT_ROUNDScharacterize the behavior in this case as well
Other Languages
Common Implementations
Many implementations round-to-nearest However, rounding to zero (ignoring the least significant bits) can
have performance advantages Changing the rounding mode of the hardware floating-point unit requires 352
FLT_ROUNDS
an instruction to be executed, which in itself is a fast instruction However, but a common side effect is to
require that the floating-point pipeline be flushed before another floating-point instruction can be issued— an
expensive operation Leaving the processor in round-to-zero mode may offer savings The IBM S/360, when
using its hexadecimal floating point representation, truncates a value when converting it to a representation
having less precision
Coding Guidelines
Like other operations on floating values, conversion can introduce a degree of uncertainty into the result
This is a characteristic of floating point; there are no specific guidelines for this situation
converted not representable
Commentary
For very small values there is always a higher and lower value that bound them The situation describes in
the C sentence can only occur if the type being demoted from is capable of representing a greater range of
exponent values than the destination type
Other Languages
In Java
Common Implementations
On many processors the result of the conversion is controlled by the rounding mode A common behavior is 352
FLT_ROUNDS
to return the largest representable value (with the appropriate sign) if rounding to zero is in force, and to
infinity (with the appropriate sign) if rounding to nearest is in force When rounding to positive or negative
Trang 22infinity, the result is either the largest representable value or infinity, depending on the sign of the resultand the sign of the infinity being rounded to Many processors also have the ability to raise some form ofoverflow exception in this situation, which can often be masked.
In signal processing applications infinity is not a sensible value to round to, and processors used for thesekinds of applications often saturate at the largest representable value
Performance is often an important issue in code performing floating-point operations (adding code to
do range checks can cause excessive performance penalties) Given the performance issue and the variety
of possible application-desired behaviors and actual processor behaviors, there is no obvious guidelinerecommendation that can be made
6.3.1.7 Real and complex
700
When a value of real type is converted to a complex type, the real part of the complex result value is determined
real type
converted to
complex by the rules of conversion to the corresponding real type and the imaginary part of the complex result value is
a positive zero or an unsigned zero
The imaginary part is never a negative zero
negative zero 615
C90
Support for complex types is new in C99
Trang 23The constructors for the complex specializations, 26.2.3, take two parameters, corresponding to the real and
imaginary part, of the matching floating-point type The default value for the imaginary part is specified as
0.0
Other Languages
The Fortran intrinsic functionCMPLXtakes a parameter that specifies the type of conversion that should occur
If noKINDis specified, the intrinsic takes the value of the default real type This intrinsic function also
provides a default imaginary value of 0i (but does not say anything about the representation of zero)
Coding Guidelines
Support for complex types is new in C99 and there is no experience based on existing usage to draw on
Are there any parallels that can be made with other constructs (with a view to adapting guidelines that have
been found to be useful for integer constants)? Some parallels are discussed next; however, no guideline
recommendation is made because usage of complex types is not sufficiently great for there to be a likely
worthwhile benefit
Conversions between integer types and real floating types, and conversions between real floating to
complex floating, both involve significant changes in developer conception and an implementation’s internal
representation However, these parallels do not appear to suggest any worthwhile guideline recommendation
A value of real type can also be converted to a complex type by adding an imaginary value of zero to
it— for instance,+0.0I(assuming an implementation supports this form of constant) However, casts are
strongly associated with conversion in developers’ minds The binary+operation may cause conversions, but
this is not its primary association The possibility that an implementation will not support this literal form of
imaginary values might be considered in itself sufficient reason to prefer the use of casts, even without the
7 glob = 1.0; /* Implicit conversion */
8 glob = (double _Complex)1.0; /* Explicit conversion */
9 glob = 1.0 + 0.0I; /* I might not be supported */
10 }
Conversion of a value having a complex type, whose two components are both constants (the standard does
not define the term complex constant), to a non-complex type is suspicious for the same reason as are other
integer
Are there any issues specifically associated with conversion to or from complex types that do not apply for
conversions between other types? It is a change of type domain At the time if writing there is insufficient
experience available, with this new type, to know whether these issues are significant
and the value of the real part is converted according to the conversion rules for the corresponding real type
Commentary
This conversion simply extracts the real part from a complex value It has the same effect as a call to the
creallibrary function A NaN value in the part being discarded does not affect the value of the result (rather
than making the result value a NaN) There are no implicit conversions defined for converting to the type
_Imaginary The library functioncimaghas to be called explicitly 1378 type specifier
syntax
Trang 24In C++the conversion has to be explicit The member functions of the complex specializations (26.2.3) return
a value that has the matching floating-point type
Other Languages
Some languages support implicit conversions while others require an explicit call to a conversion function
6.3.1.8 Usual arithmetic conversions
The operators referred to here could be either unary or binary operators In the case of the unary operatorsthe standard specifies no conversion if the operand has a floating type (although the implementation mayperform one, as indicated by the value of theFLT_EVAL_METHODmacro) However, there is a conversion (theFLT_EVAL_METHOD354
integer promotions) if the operand has an integer type
Other Languages
All languages that support more than one type need to specify the behavior when an operator is givenoperands whose types are not the same Invariably the type that can represent the widest range of valuestends to be chosen
Coding Guidelines
Readers needing to comprehend the evaluation of an expression in detail, need to work out which conversions,
if any, are carried out as a result of the usual arithmetic conversions (and the integer promotions) Thisevaluation requires readers to apply a set of rules Most developers are not exposed on a regular basis to
a broad combination of operand type pairs Without practice, developers’ skill in deducing the result ofthe usual arithmetic conversions on the less commonly encountered combinations of types will fade away(training can only provide a temporary respite) The consequences of this restricted practice is that developersnever progress past the stage of remembering a few specific cases
If a single integer type were used, the need for developers to deduce the result of the usual arithmeticconversions would be removed This is one of the primary rationales behind the guideline recommendationthat only a single integer type be used
The purpose is to determine a common real type for the operands and result
common real type
Commentary
This defines the term common real type The basic idea is that both types are converted to the real typecapable of holding the largest range of values (mixed signed/unsigned types are the fly in the ointment)
Trang 25In the case of integer types, the type with the largest rank is chosen For types with the same rank, the
conversions are unsigned preserving
Many processor instructions operate on values that have the same type (or at least are treated as if they
did) C recognizes this fact and specifies how the operands are to be converted This process also removes
the need to enumerate the behavior for all possible permutations of operand type pairs
C90
The term common real type is new in C99; the equivalent C90 term was common type
Other Languages
The need to convert the operands to the same type is common to languages that have a large number of
different arithmetic types There are simply too many permutations of different operand type pairs to want to
enumerate, or expect developers to remember, the behavior for all cases Some languages (e.g., PL/1) try
very hard to implicitly convert the operands to the same type, without the developer having to specify any
explicit conversions Other languages (e.g., Pascal) enumerate a small number of implicit conversions and
require the developer to explicitly specify how any other conversions are to be performed (by making it a
constraint violation to mix operands having other type pairs)
Common Implementations
On some processors arithmetic operations can produce a result that is wider than the original operands—
for instance multiplying two 16-bit values to give a 32-bit result In these cases C requires that the result
be converted back to the same width as the original operands Such processor instructions also offer the
potential optimization of not performing the widening to 32 bits before carrying out the multiplication Other
operand/result sizes include 8/16 bits
Coding Guidelines
The C90 term common type is sometimes used by developers Given that few developers will ever use
complex types it is unlikely that there will be a general shift in terminology usage to the new C90 term
Some developers make the incorrect assumption that if the two operands already have a common type, the
usual arithmetic conversions are not applied They forget about the integer promotions For instance, two
operands of typeshortare both promoted tointbefore the usual arithmetic conversions are applied
Pointing out to developers that the integer promotions are always performed is a training issue (explicitly
pointing out this case may help prevent developers from making this assumption) Following the guideline
on using a single integer type ensures that incorrect developer assumptions about this promotion do not affect 480.1 object
int type only
the intended behavior
6 * Experience shows that many developers expect the following additional and
7 * relational operations to be performed on character types, rather than int.
corresponding real type is the common real type
Trang 26The result, 6.0 + ∞i, is what the developer probably expected Now assume that the usual arithmeticconversions were defined to change the type domain of the operands, a real type having 0.0i added to it whenconverting to a complex type In this case, we get:
2.0 ∗ (3.0 + ∞i) ⇒ (2.0 + 0.0i) ∗ (3.0 − ∞i) (704.3)(2.0 ∗ 3.0 − 0.0 ∗ ∞) + (2.0 ∗ ∞ + 0.0 ∗ 3.0)i ⇒ N aN + ∞i (704.4)The result, N aN + ∞i, is probably a surprise to the developer For imaginary types:
The term type domain is new in C99 and is not defined in the C++Standard
The template classcomplexcontain constructors that can be used to implicitly convert to the matchingcomplex type The operators defined in these templates all return the appropriate complex type
C++converts all operands to a complex type before performing the operation In the above example the Cresult is 6.0 + ∞i, while the C++result is NAN + ∞i
The only place where the standard explicitly stated otherwise is in the discussion of imaginary types in annex
G Support for such types, by an implementation, is optional When one operand has a complex type and theother operand does not, the latter operand is not converted to a different type domain (although its real typemay be changed by a conversion), so there is no common arithmetic type, only a common real type
footnote
51719
Trang 27Thecomplexspecializations (26.2.3) define conversions forfloat,doubleandlong doubleto complex
classes A number of the constructors are defined as explicit, which means they do not happen implicitly,
they can only be used explicitly The effect is to create a different result type in some cases
In C++, if the one operand does not have a complex type, it is converted to the corresponding complex type,
and the result type is the same as the other operand having complex type See footnote 51 719footnote51
Other Languages
The result type being the same as the final type of the operands is true in most languages
conversions
Commentary
This defines the term usual arithmetic conversions There are variations on this term used by developers;
however, arithmetic conversions is probably the most commonly heard
Other Languages
The equivalent operations in Java are known as the Binary Numeric Promotion
Common Implementations
In some cases the standard may specify two conversions— an integer promotion followed by an arithmetic
conversion An implementation need not perform two conversions The as-if rule can be used to perform a
single conversion (if the target processor has such an instruction available to it) provided the final result is
the same
Coding Guidelines
The concept of usual arithmetic conversions is very important in any source that has operands of different
types occurring together in the same expression The guideline recommendation specifying use of a single
integer type is an attempt to prevent this from occurring The general issue of whether any operand that is 480.1 object
int type only
converted should be explicitly cast, rather than implicitly converted, is discussed elsewhere 653 operand
convert cally
conversions long double
Processors often support an instruction for converting a value having a particular integer type to a floating
representation Implementations have to effectively promote integer values to this type before they can be
converted to a floating type Since the integer type is usually the widest one available, there is rarely an
externally noticeable difference
Coding Guidelines
If both operands have a floating type, there is no loss of precision on the conversion 695floatpromoted to
double or long double
When an integer is converted to a real type, there may be some loss of precision The specific case of688 integer
conversion to floating
integer-to-floating conversion might be considered different from integer-to-integer and floating-to-floating
conversions for a number of reasons:
• There is a significant change of representation 688integerconversion to
floating
Trang 28• The mixing of operands having an integer and floating type is not common (the implication being thatmore information will be conveyed by an explicit cast in this context than in other contexts).
• The decision to declare an object to have a floating type is a much bigger one than giving it an integertype (experience suggests that, once this decision is made, it is much less likely to change than had aninteger type has been chosen, for which there are many choices; so the maintenance issue of keepingexplicit conversions up to date might be a smaller one than for integer conversions)
motions
675
permutations of operand types that the standard needs to specify behavior for
Other Languages
Most languages have a small number of arithmetic types, and it is practical to fully enumerate the behavior
in all cases, making it unnecessary to define an intermediate step
Trang 29types are the same There is no obvious guideline recommendation that can render this oversight (or lack of
712 operand same type
no further sion
conver-knowledge on the part of developers) harmless If the guideline recommendation specifying use of a single
integer type is followed these promotions will have no effect 480.1 object
int type only
Usage
Usage information on integer promotions is given elsewhere (see Table675.1)
conversions integer types
Commentary
The C90 Standard enumerated each case based on type Now the that concept of rank has been introduced, it
is possible to specify rules in a more generalized form This generalization also handles any extended integer
types that an implementation may provide
C++
The rules in the C++Standard appear in a bulleted list of types with an implied sequential application order
Common Implementations
In those implementations where the two types have the same representation no machine code, to perform the
conversion at execution time, need be generated
While the standard may specify a two-stage conversion process, some processors support instructions that
enable some of the usual arithmetic conversions to be performed in a single instruction
Coding Guidelines
Developers have a lot of experience in dealing with the promotion and conversion of the standard integer
types In the C90 Standard the rules for these conversions were expressed using the names of the types, while 493 standard
integer typesC99 uses the newly created concept of rank Not only is the existing use of extended integer types rare (and 659 conversion
rank
so developers are unlikely to be practiced in their use), but conversions involving them use rules based on
their rank (which developers will have to deduce) At the time of this writing there is insufficient experience
available with extended integer types to be able to estimate the extent to which the use of operands having
some extended type will result in developers incorrectly deducing the result type For this reason these coding
guidelines sections say nothing more about the issue (although if the guideline recommendation specifying
use of a single integer type is followed the promotion of extended integer types does not become an issue) 480.1 object
int type only
For one of the operands, these conversions can cause either its rank to be increased, its sign changed, or
both of these things An increase in rank is unlikely to have a surprising affect (unless performance is an
issue, there can also be cascading consequences in that the result may need to be converted to a lesser rank
later) A change of sign is more likely to cause a surprising result to be generated (i.e., a dramatic change in
the magnitude of the value, or the reversal of its signedness) While 50% of the possible values an object can
represent may produce a surprising result when converted between signed/unsigned, in practice the values
that occur are often small and positive (see Table940.4)
Experience has shown that mixing operands having signed and unsigned types in expressions has a benefit
Despite a great deal of effort, by a large number of people, no guideline recommendation having a cost less
than that incurred by the occasional surprising results caused by the arithmetic conversions has been found
Usage
Usage information on implicit conversions is given elsewhere (see Table653.1)
same type
no further conversion
Commentary
Both operands can have the same type because they were declared to have that type, the integer promotions
converted them to that type, or because they were explicitly cast to those types
Trang 30For language lawyers only: A subtle difference in requirements exists between the C90 and C99 Standard(which in practice would have been optimized away by implementations) The rules in the C90 wording wereordered such that when two operands had the same type, except when both had typeint, a conversion wasrequired So the typeunsigned longneeded to be converted to anunsigned long, or alongto along,
or anunsigned intto anunsigned int
Coding Guidelines
Many developers incorrectly assume this statement is true for all integer types, even those types whose rank isless than that of typeint They forget, or were never aware, that the integer promotions are always performed.integer pro-
unsigned of the other operand, then the operand with signed integer type is converted to the type of the operand with
unsigned integer type
Trang 311 signed int si;
2 unsigned long ul;
operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of
the operand with signed integer type
Commentary
This rule is worded in terms of representable values, not rank It preserves the value of the operand, but not
its signedness While a greater range of representable values does map to greater rank, the reverse is not true
It is possible for types that differ in their rank to have the same range of representable values The case of
same representation is covered in the following rule
Other Languages
Most languages have a single integer type Those that support an unsigned type usually only have one of
them A rule like this one is very unlikely to be needed
Common Implementations
In this case an implementation need not generate any machine code The translator can simply regard the
value as having the appropriate signed integer type
Example
In the following addition two possible combinations of representation yield the conversions:
1 16-bit unsigned int plus 32-bit long ⇒ 32-bit long
2 32-bit unsigned int plus 32-bit long ⇒ this rule not matched
1 unsigned int ui;
with signed integer type
Commentary
This rule is only reached when one operand is an unsigned integer type whose precision is greater than or
equal to the precision of a signed type having a greater rank This can occur when two standard types have
the same representation, or when the unsigned type is an extended unsigned integer type (which must have a
lesser rank than any standard integer type having the same precision) In this rule the result type is different
from the type of either of the operands The unsignedness is taken from one operand and the rank from
another to create the final result type This rule is the value-driven equivalent of the rank-driven rule specified
previously
714 signed integer converted to unsigned
Trang 32Coding Guidelines
This result type of this rule is likely to come as a surprise to many developers, particularly since it is dependent
on the width and precision of the operands (because of the previous rule) Depending on the representation ofinteger types used, the previous rule may match on one implementation and this rule match on another Theresult of the usual arithmetic conversions, in some cases, is thus dependent on the representation of integertypes
A previous rule dealt with operands being converted from a signed to an unsigned type For the rule
10 * 16-bit unsigned int + 32-bit signed long -> 32-bit signed long
11 * 32-bit unsigned int + 32-bit signed long -> 32-bit unsigned long
Trang 331 #include <complex.h> // the equivalent C++ header
8 fc + d /* Result has type double complex */
9 // Result has type complex<float>.
To be exact an implementation is required to generate code that behaves as if the specified conversions
were performed An implementation can optimize away any conversion if it knows that the current value
representation is exactly the same as the type converted to (implicitly or explicitly) When an implementation
carries out floating-point operations to a greater precision than required by the semantic type, the cast operator
is guaranteed to return a result that contains only the precision required by the type converted to An explicit
cast provides a filter through which any additional precision cannot pass
The assignment operator copies a value into an object The object will have been allocated sufficient
storage to be able to hold any value representable in its declared type An implementation therefore has to
scrape off any additional precision which may be being held in the value (i.e., if the register holding it has
more precision), prior to storing a value into an object
Passing an argument in a function call, where a visible prototype specifies a parameter type of less
floating-point precision, is also required to perform these conversions
Other Languages
A universal feature of strongly typed languages is that the assignment operator is only able to store a value
into an object that is representable in an object’s declared type Many of these languages do not get involved
in representation details They discuss the cast operator, if one is available, in terms of change of type and
tend to say nothing about representation issues
In some languages the type of the value being assigned becomes the type of the object assigned to For
such language objects are simply labels for values and have no identity of their own, apart from their name
(and they may not even have that)
6.3.2 Other operands
6.3.2.1 Lvalues, arrays, and function designators
lvalue
Trang 34> Part of the problem is that the term "lvalue" is being used for two
> different notions, one syntactic (a certain class of expressions) and
> the other semantic (some abstraction of the notion of "address") The
> first step would be to remove this ambiguity by selecting distinct
> terms for these two notions, e.g., "lvalue-expression" for the
> syntactic notion and "lvalue" for the semantic notion.
>
> The syntactic notion could be defined by suitably amending the grammar
> appendix so that lvalue-expression is a non-terminal whose expansions
> are exactly the expressions that can appear on the left side of an
> assignment without causing a compile-time error.
>
.
> Tom Payne This is true To clean up the history a bit: The 1967 BCPL manual I have uses the words "lvalue" and "rvalue" liberally; my copy does not have a consolidated grammar, but the section about Simple Assignment Commands describes the syntactical possibilities for things on the left of := , namely an identifier (not a manifest constant), a vector application, or an rv expression (equivalent to C *, or later BCPL
!) However, "lvalue" in the text does indeed seem to be a semantic notion, namely a bit pattern that refers to a cell in the abstract machine.
The Richards and Whitbey-Strevens book (my printing seems post-1985, but it’s a reprint of the 1980 edition) does not seem to use the terms lvalue or rvalue On the other hand, it does make even more explicit syntactically (in its grammar) what can appear on the LHS of the := of an assignment-command, namely an <lhse> or left-hand-side
expression This is the syntactic lvalue.
On yet another hand, it only indirectly and by annotation says that the operand of the address-of operator is restricted Nevertheless, the textual description seems identical to the consolidated grammar’s
Dennis
C90
Trang 35An lvalue is an expression (with an object type or an incomplete type other thanvoid) that designates an
object.31)
The C90 Standard required that an lvalue designate an object An implication of this requirement was that
some constraint requirements could only be enforced during program execution (e.g., the left operand of an
assignment operator must be an lvalue) The Committee intended that constraint requirements be enforceable
1289 assignment operator modifiable lvalue
during translation
Technically this is a change of behavior between C99 and C90 But since few implementations enforced
this requirement during program execution, the difference is unlikely to be noticed
C++
3.10p2
An lvalue refers to an object or function
Incomplete types, other thanvoid, are object types in C++, so all C lvalues are also C++lvalues 475 object typesThe C++support for a function lvalue involves the use of some syntax that is not supported in C
While not being generic to programming languages, the concept of lvalue is very commonly seen in the
specification of other languages
Commentary
This can occur if a dereferenced pointer does not refer to an object, or perhaps it refers to an object whose
of object
C90
In the C90 Standard the definition of the term lvalue required that it designate an object An expression could
not be an lvalue unless it designated an object
C++
In C++the behavior is not always undefined:
3.8p6
Similarly, before the lifetime of an object has started but after the storage which the object will occupy has been
allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused
or released, any lvalue which refers to the original object may be used but only in limited ways Such an lvalue
refers to allocated storage (3.7.3.2), and using the properties of the lvalue which do not depend on its value is
well-defined
Coding Guidelines
A guideline recommending that an lvalue always denote an object when it is evaluated is equivalent to a
guideline recommending that programs not contain defects
Example
Trang 36in C99 to provide a more precise specification of an object’s type.
C++
The situation in C++is rather more complex:
1.8p1 The constructs in a C++program create, destroy, refer to, access, and manipulate objects An object is a region of
storage [Note: A function is not an object, regardless of whether or not it occupies storage in the way that objects
(12.2) when needed The properties of an object are determined when the object is created An object can have
polymorphic(10.3); the implementation generates information associated with each such object that makes itpossible to determine that object’s type during program execution For other objects, the interpretation of the
Trang 37The result of a cast is not an lvalue, so it is not possible to cast away a const-qualification However, it is1131 footnote
4 * The const qualifier applies to the array
5 * element, not to the array a_mem.
The term modifiable lvalue is used by the C++Standard, but understanding what this term might mean
requires joining together the definitions of the terms lvalue and modifiable:
3.10p10
An lvalue for an object is necessary in order to modify the object except that an rvalue of class type can also be
used to modify its referent under certain circumstances
3.10p14
If an expression can be used to modify the object to which it refers, the expression is called modifiable
There does not appear to be any mechanism for modifying objects having an incomplete type
8.3.4p5
Objects of array types cannot be modified, see 3.10
This is a case where an object of a given type cannot be modified and follows the C requirement
7.1.5.1p3
; a const-qualified access path cannot be used to modify an object even if the object referenced is a non-const
object and can be modified through some other access path
The C++ wording is based on access paths rather than the C method of enumerating the various cases
However, the final effect is the same
Other Languages
Many languages only provide a single way of modifying an object through assignment In these cases a
general term describing modifiability is not required; the requirements can all be specified under assignment
Languages that support operators that can modify the value of an object, other than by assignment, sometimes
define a term that serves a purpose similar to modifiable lvalue
converted
to value
converted to the value stored in the designated object (and is no longer an lvalue)
Commentary
The exceptions called out here apply either because information on the storage for an object is used or are
situations where there is a possibility for the lvalue to be modified (in the case of the&and.operators this
may occur in a subsequent operation) In the case of an array type, in most contexts, a reference to an object 729arrayconverted to
pointer
having this type is converted to a pointer to its first element (and so is always an lvalue) This converted
Trang 38Quite a long chain of deduction is needed to show that this requirement also applies in C++ The C++Standarduses the term rvalue to refer to the particular value that an lvalue is converted into
3.10p7 Whenever an lvalue appears in a context where an rvalue is expected, the lvalue is converted to an rvalue;
the lvalue-to-rvalue (4.1), standard conversions are applied to convert the expression to an rvalue
The C wording specifies that lvalues are converted unless they occur in specified contexts The C++wordingspecifies that lvalues are converted in a context where an rvalue is expected Enumerating the cases where
C++expects an rvalue we find:
5.3.4p4 The lvalue-to-rvalue (4.1), standard conversions are not applied to the operand ofsizeof
What is the behavior for the unary&operator?
However, this is a Note: and has no normative status There is no mention of any conversions in 5.3.1p2-5,which deals with the unary&operator
In the case of the postfix++and operators we have:
5.2.6p1 The operand shall be a modifiable lvalue The result is an rvalue
In the case of the prefix++and operators we have:
5.3.2p1 The operand shall be a modifiable lvalue The value is the new value of the operand; it is an lvalue
So for the postfix case, there is an lvalue-to-rvalue conversion, although this is never explicitly stated and inthe prefix case there is no conversion
The C case is more restrictive than C++, which requires a conforming implementation to successfully translate:
For the left operand of the.operator we have:
5.2.5p4 IfE1is an lvalue, thenE1.E2is an lvalue
The left operand is not converted to an rvalue For the left operand of an assignment operator we have:
5.17p1 All require a modifiable lvalue as their left operand, ; the result is an lvalue
The left operand is not converted to an rvalue And finally for the array type:
4.1p1
Trang 39Figure 725.1: Execution-time counts of the number of reads and writes of the same object (declared in block or file scope, i.e.,
not allocated storage) for a subset of the MediaBench benchmarks; items above the diagonal indicate more writes than reads.
Data kindly supplied by Caspi, based on his research.[208]
An lvalue having an array type cannot be converted to an rvalue (i.e., the C++Standard contains no other
wording specifying that an array can be converted to an rvalue)
In two cases the C++Standard specifies that lvalue-to-rvalue conversions are not applied: Clause 5.18p1
left operand of the comma operator and Clause 6.2p1 the expression in an expression statement In C the
values would be discarded in both of these cases, so there is no change in behavior In the following cases
C++performs a lvalue-to-rvalue conversion (however, the language construct is not relevant to C): Clause
8.2.8p3 Type identification; 5.2.9p4 static cast; 8.5.3p5 References
Other Languages
The value that the lvalue is converted into is sometimes called an rvalue in other languages
Coding Guidelines
The distinction between lvalue and rvalue and the circumstances in which the former is converted into the
latter is something that people learning to write software for the first time often have problems with But
once the underlying concepts are understood, developers know how to distinguish the two contexts The
confusion that developers often get themselves into with pointers is the pointer or the pointed-to object being
accessed is a separate issue and is discussed under the indirection operator 1095 unary *
un-Commentary
Type qualification only applies to objects, not to values A pointer value can refer to an object having a
qualified type In this case it is not the pointer value that is qualified
1 extern int glob;
2 extern const int *p_1;
3 extern int * const p_2 = &glob; /* The value of p_2 cannot be modified */
Trang 40The value being referred to in C is what C++calls an rvalue.
4.1p1 IfTis a non-class type, the type of the rvalue is the cv-unqualified version ofT Otherwise, the type of the rvalue
isT.49)
Footnote 49 49) In C++class rvalues can have cv-qualified types (because they are objects) This differs fromISO C, in which
non-lvalues never have cv-qualified types
Class rvalues are objects having a structure or union type in C
Other Languages
Some languages give string literals their equivalent of aconstqualifier, thus making it possible for values to
be qualified, as well as have a type
4.1p1 An lvalue (3.10) of a non-function, non-array typeTcan be converted to an rvalue IfTis an incomplete type, a
program that necessitates this conversion is ill-formed
4.2p1 An lvalue or rvalue of type “array of NT” or “array of unknown bound ofT” can be converted to an rvalue of
The C behavior in this case is undefined; in C++the conversion is ill-formed and a diagnostic is required