1. Trang chủ
  2. » Công Nghệ Thông Tin

Tài liệu The New C Standard- P7 pptx

100 325 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Boolean, Characters, And Integers
Trường học University of C
Chuyên ngành Computer Science
Thể loại Tài liệu
Năm xuất bản 2009
Thành phố City Name
Định dạng
Số trang 100
Dung lượng 842,85 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

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 1

Why 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 2

The 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 3

the 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 4

54) 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 5

673If 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 6

1 #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 7

Common 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 8

in 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 9

5 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 10

Coding 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 11

Common 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 12

4.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 13

The 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 14

In 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 16

4.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 17

repre-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 18

Coding 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 19

The 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 20

Although 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 21

The 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 22

infinity, 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 23

The 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 24

In 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 25

In 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 26

The 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 27

Thecomplexspecializations (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 29

types 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 30

For 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 31

1 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 32

Coding 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 33

1 #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 35

An 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 36

in 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 37

The 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 38

Quite 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 39

Figure 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 40

The 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

Ngày đăng: 26/01/2014, 07:20