The New C Standard- P7

Chia sẻ: Thanh Cong | Ngày: | Loại File: PDF | Số trang:100

lượt xem

The New C Standard- P7

Mô tả tài liệu
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

Tham khảo tài liệu 'the new c standard- p7', công nghệ thông tin, kỹ thuật lập trình phục vụ nhu cầu học tập, nghiên cứu và làm việc hiệu quả

Chủ đề:

Nội dung Text: The New C Standard- P7

  1. Boolean, characters, and integers 668 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 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 C++ The C++ Standard specifies no requirements on how an implementation might extend the available integer types. 665 — The rank of char shall equal the rank of signed char and unsigned char. char rank Commentary This statement is needed because the type char is distinct from that of the types signed char and unsigned char. 537 char separate type 666 — The rank of _Bool shall be less than the rank of all other standard integer types. _Bool rank Commentary This does not imply that the object representation of the type _Bool contains a smaller number of bits than 593 unsigned any other integer type (although its value representation must). integer types object representa- tion C++ As described below, bool values behave as integral types. 3.9.1p6 An rvalue of type bool can be converted to an rvalue of type int, with false becoming zero and true becoming 4.5p4 one. The C++ Standard places no requirement on the relative size of the type bool with 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 type long. Other Languages Boolean types, if supported, are usually viewed as the smallest type, irrespective of the amount of storage used to represent them. 667 — The rank of any enumerated type shall equal the rank of the compatible integer type (see rank enumerated type Commentary 1447 enumeration The compatible integer type can vary between different enumerated types. An enumeration constant has type type compatible with int. There is no requirement preventing the rank of an enumerated type from being less than, or greater than, 1441 enumerators type int the rank of int. Other Languages 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. 668 — The rank of any extended signed integer type relative to another extended signed integer type with the rank extended in- same precision is implementation-defined, but still subject to the other rules for determining the integer teger relative conversion rank. to extended June 24, 2009 v 1.2
  2. 670 Boolean, characters, and integers Commentary The reasons why an implementation might provide two extended signed integer types of the same precision rank 664 is the same as the reasons why it might provide such a type having the same precision as a standard integer standard in- teger relative type. Existing practice provides a ranking for the standard integer types (some or all of which may have the to extended rank 662 same precision). standard in- teger types C++ The C++ Standard does not specify any properties that must be given to user-defined classes that provide some form of extended integer type. Coding Guidelines rank 664 standard in- teger relative The same issues apply here as applied to the extended integer types in relation to the standard integer types. to extended rank — For all integer types T1, T2, and T3, if T1 has greater rank than T2 and T2 has greater rank than T3, then T1 669 transitive has greater rank than T3. Commentary The rank property is transitive. expression The following may be used in an expression wherever an int or unsigned int may be used: 670 wherever an int may be used Commentary An int can be thought of as the smallest functional unit of type for arithmetic operations (the types with integer pro- 675 motions greater rank being regarded as larger units). This observation is a consequence of the integer promotions. Any integer type can be used in an expression wherever an int or unsigned int may be used (this may involve them being implicitly converted). However, operands having one of the types specified in the following sentences will often return the same result if they also have the type int or unsigned int. C90 The C90 Standard listed the types, while the C99 Standard bases the specification on the concept of rank. A char, a short int, or an int bit-field, or their signed or unsigned varieties, or an enumeration type, may be used in an expression wherever an int or unsigned int may be used. C++ C++ supports the overloading of operators; for instance, a developer-defined definition can be given to the binary + operator, when applied to operands having type short. Given this functionality, this C sentence cannot be said to universally apply to programs written in C++. It is not listed as a difference because it requires use of C++ functionality for it to be applicable. The implicit conversion sequences are specified in clause When there are no overloaded operators visible (or to be exact no overloaded operators taking arithmetic operands, and no user-defined conversion involving arithmetic types), the behavior is the same as C. Other Languages Most other languages do not define integer types that have less precision than type int, so they do not contain an equivalent statement. The type char is usually a separate type and an explicit conversion is needed if an operand of this type is required in an int context. Coding Guidelines object 480.1 int type only If the guideline recommendation specifying use of a single integer type is followed, this permission will integer pro- 675 never be used. motions v 1.2 June 24, 2009
  3. Boolean, characters, and integers 671 Example In the following: 1 #include 2 3 typedef unsigned int T; 4 T x; 5 6 int f(void) 7 { 8 if (sizeof(x) == 2) 9 return (x
  4. 673 Boolean, characters, and integers 54) As a consequence, operands of type bool, wchar_t, or an enumerated type are converted to some integral type. The C++ Standard does not appear to contain explicit wording giving this permission for other occurrences of operands (e.g., to unary operators). However, it does not contain wording prohibiting the usage (the wording for the unary operators invariably requires the operand to have an arithmetic or scalar type). Other Languages The few languages that do support more than one integer type specify their own rules for when different types can occur in an expression at the same time. bit-field — A bit-field of type _Bool, int, signed int, or unsigned int. 672 in expression Commentary bit-field 1393 A bit-field is a method of specifying the number of bits to use in the representation of an integer type. The maximum width type used in a bit-field declaration specifies the set of possible values that might be available, while the constant value selects the subset (which can include all values) that can be represented by the member. Because the integer promotion rules are based on range of representable values, not underlying signedness of the type, it is possible for a member declared as a bit-field using an unsigned type to be promoted to the type signed int. C90 Support for bit-fields of type _Bool is new in C99. C++ An rvalue for an integral bit-field (9.6) can be converted to an rvalue of type int if int can represent all the 4.5p3 values of the bit-field; otherwise, it can be converted to unsigned int if unsigned int can 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 an enumerated 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 type int, or bit-fields having an enumerated type. Other Languages Languages, such as Pascal and Ada, provide developers with the ability to specify the minimum and maximum values that need to be represented in an integer type (a bit-field specifies the number of bits in the representation, not the range of values). These languages contain rules that specify how objects defined to have 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 unit holding the bit-field has to be loaded, invariably into a register. Those bits not associated with the bit-field being read then need to be removed. This can involve using a bitwise-and instruction to zero out bits and right shift 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 complex instructions went out of fashion when RISC design philosophy first took off, but they have started to make a come 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 multimedia benchmarks by between 0.39% and 8.67% (code size reductions were between 1.27% and 21.05%). v 1.2 June 24, 2009
  5. Boolean, characters, and integers 674 673 If an int can represent all values of the original type, the value is converted to an int; int can repre- sent values Commentary converted to int 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.) Other Languages Most languages have a single signed integer type, so there is rarely a smaller integer type that needs implicit conversion. Coding Guidelines Some developers incorrectly assume that objects declared using typedef names do not take part in the integer typedef assumption promotions. Incorrect assumptions by a developer are very difficult to deduce from an analysis of the source of no integer code. In some cases the misconception will be harmless, the actual program behavior being identical to promotions the misconstrued behavior. In other cases the behavior is different. Guideline recommendations are not a substitute for proper developer training. Example 1 typedef short SHORT; 2 3 extern SHORT es_1, 4 es_2; 5 6 void f(void) 7 { 8 unsigned int ui = 3; /* Value representable in a signed int. */ 9 10 if (es_1 == (es_2 + 1)) /* Operands converted to int. */ 11 ; 12 if (ui > es_1) /* Right operand converted to unsigned int. */ 13 ; 14 } 674 otherwise, it is converted to an unsigned int. int cannot rep- resent values Commentary converted to unsigned int This can occur for the types unsigned short, or unsigned char, if either of them has the same represen- tation as an unsigned 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 type unsigned int. Common Implementations On 16-bit processors the types short and int usually have the same representation, so unsigned short promotes to unsigned int. On 32-bit processors the type short usually has less precision than int, so the type unsigned short promotes to int. There are a few implementations, mostly on DSP-based processors, where the character types have the same width as the type int.[984] Coding Guidelines Existing source code ported, from an environment in which the type int has greater width than short, 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 type int is greater than the width of short: June 24, 2009 v 1.2
  6. 675 Boolean, characters, and integers 1 #include 2 3 extern unsigned short us; 4 extern signed int si; /* Can hold negative values. */ 5 6 void f(void) 7 { 8 if (us > si) 9 printf("Pass\n"); 10 else 11 printf("Fail\n"); 12 } the object us will be promoted to the type int. There will not be any change of values. On a host where the types int and short have the same width, an unsigned short will be promoted to unsigned int. This will lead to si being promoted to unsigned int (the usual arithmetic conversions) and a potential change in its value. (If it has a small negative value, it will convert to a large positive value.) The relational comparison will then return a different result than in the previous promotion case. Cg 674.1 An object having an unsigned integer type shall not be implicitly converted to unsigned int through the application of the integer promotions. The consequence of this guideline recommendation is that such conversions need to be made explicit, using a cast to an integer type whose rank is greater than or equal to int. integer promo- These are called the integer promotions.48) 675 tions Commentary This defines the term integer promotions. Integer promotions occur when an object having a rank less than footnote 690 int appears in certain contexts. This behavior differs from arithmetic conversions where the type of a 48 different object is involved. Integer promotions are affected by the relative widths of types (compared to the width of int). If the type int has greater width than short then, in general (the presence of extended integer types whose rank is also less than int can complicate the situation), all types of less rank will convert to int. If short has the same precision as int, an unsigned short will invariably promote to an unsigned 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 signed int 24 bits including sign unsigned int 32 bits Your author does not know of any implementation that uses this kind of unusual combination of bits for its integer type representation. C90 These are called the integral promotions.27) C++ The C++ Standard uses the C90 Standard terminology (and also points out, 3.9.1p7, “A synonym for integral type is integer type.”). Other Languages The unary numeric promotions and binary numeric promotions in Java have the same effect. v 1.2 June 24, 2009
  7. Boolean, characters, and integers 676 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 to int). On processors having instructions that operate on values having a type narrower than int more efficiently than type int, 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 type int, or unsigned int. Coding Guidelines 480.1 object If the guideline recommendation specifying use of a single integer type is followed there would never be any int type only integer promotions. The issue of implicit conversions versus explicit conversions might be a possible cause 653 operand of a deviation from this recommendation and is discussed elsewhere. convert automati- cally Example 1 signed short s1, s2, s3; 2 unsigned short us1, us2, us3; 3 4 void f(void) 5 { 6 s1 = s2 + s3; /* 7 * The result of + may be undefined. 8 * The conversion for the = may be undefined. 9 */ 10 /* s1 = (short)((int)s2 + (int)s3); */ 11 s1 = us2 + s3; /* The conversion for the = may be undefined. */ 12 /* 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). 16 * 17 * Either both shorts promote to a wider type: 18 * 19 * s1 = (short)((int)us2 + (int)s3); 20 * 21 * or they both promote to an unsigned type of the same width: 22 * 23 * s1 = (short)((unsigned int)us2 + (unsigned int)s3); 24 */ 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. Original Type % Original Type % unsigned char 2.3 char 1.2 unsigned short 1.9 short 0.5 676 All other types are unchanged by the integer promotions. June 24, 2009 v 1.2
  8. 677 Boolean, characters, and integers Commentary The integer promotions are only applied to values whose integer type has a rank less than that of the int type. C++ This is not explicitly specified in the C++ Standard. However, clause 4.5, Integral promotions, discusses no other types, so the statement is also true in C++ value preserving The integer promotions preserve value including sign. 677 Commentary These rules are sometimes known as value preserving promotions. They were chosen by the Committee because they result in the least number of surprises to developers when applied to operands. The promoted value would remain unchanged whichever of the two rules used by implementations were used. However, in many cases this promoted value appears as an operand of a binary operator. If unsigned preserving promotions were used (see Common implementations below), the value of the operand could have its sign changed (e.g., if the operands had types unsigned char and signed char, both their final operand type would have been unsigned int), potentially leading to a change of that value (if it was negative). The unsigned 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 a change of value, something that is likely to be unexpected. Value preserving rules can also produce results that are unexpected, but these occur much less often. Rationale The unsigned preserving rules greatly increase the number of situations where unsigned int confronts signed int to yield a questionably signed result, whereas the value preserving rules minimize such confrontations. Thus, the value preserving rules were considered to be safer for the novice, or unwary, programmer. After much 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. Other Languages This is only an issue for languages that contain more than one signed integer type and an unsigned integer type. Common Implementations base doc- 1 The base document specified unsigned preserving rules. If the type being promoted was either unsigned ument char or unsigned short, it was converted to an unsigned int. The corresponding signed types were promoted to signed int. Some implementations provide an option to change their default behavior to follow unsigned preserving rules.[610, 1342, 1370] Coding Guidelines Existing, very old, source code may rely on using the unsigned preserving rules. It can only do this if the translator is also running in such a mode, either because that is the only one available or because the translator is running in a compatibility mode to save on the porting (to the ISO rules) cost. Making developers aware of any of the issues involved in operating in a nonstandard C environment is outside the scope of these coding guidelines. Example 1 extern unsigned char uc; 2 3 void f(void) 4 { v 1.2 June 24, 2009
  9. Boolean type 680 5 int si = -1; 6 /* 7 * Value preserving rules promote uc to an int -> comparison succeeds. 8 * 9 * Signed preserving rules promote uc to an unsigned int, usual arithmetic 10 * conversions then convert si to unsigned int -> comparison fails. 11 */ 12 if (uc > si) 13 ; 14 } 678 As discussed earlier, whether a “plain” char is treated as signed is implementation-defined. char plain treated as Commentary 516 char repre- range, The implementation-defined treatment of “plain” char will only affect the result of the integer promotions if sentation and behavior any of the character types can represent the same range of values as an object of type int or unsigned int. 679 Forward references: enumeration specifiers (, structure and union specifiers ( Boolean type 680 When any scalar value is converted to _Bool, the result is 0 if the value compares equal to 0; _Bool converted to Commentary Converting a scalar value to type _Bool is effectively the same as a comparison against 0; that is, (_Bool)x is effectively the same as (x != 0) except in the latter case the type of the result is int. Conversion to _Bool is different from other conversions, appearing in a strictly conforming program, in that it is not commutative— (T1)(_Bool)x need 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 _Bool is new in C99. C++ An rvalue of arithmetic, enumeration, pointer, or pointer to member type can be converted to an rvalue of type 4.12p1 bool. A zero value, null pointer value, or null member pointer value is converted to false; The value of false is not defined by the C++ Standard (unlike true, it is unlikely to be represented using any value other than zero). But in contexts where the integer conversions are applied: . . . the value false is converted to zero . . . 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. June 24, 2009 v 1.2
  10. 682 Signed and unsigned integers Coding Guidelines The issue of treating boolean values as having a well-defined role independent of any numeric value is boolean role 476 discussed elsewhere; for instance, treating conversions of values to the type _Bool as representing a change of role, not as representing the values 0 and 1. The issue of whether casting a value to the type _Bool, rather than comparing it against zero, represents an idiom that will be recognizable to C developers is discussed boolean role 476 elsewhere. otherwise, the result is 1. 681 Commentary if statement 1744 operand com- pare against 0 In some contexts C treats any nonzero value as representing true — for instance, controlling expressions (which are also defined in terms of a comparison against zero). A conversion to _Bool reduces all nonzero values to the value 1. C++ . . . ; any other value is converted to true. 4.12p1 The value of true is not defined by the C++ Standard (implementations may choose to represent it internally using any nonzero value). But in contexts where the integer conversions are applied: . . . the value true is converted to one. 4.7p4 Signed and unsigned integers When a value with integer type is converted to another integer type other than _Bool, if the value can be 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 and specify the behavior of all conversions. For integer types this means that the value has to be within the range numeri- 300 specified by the corresponding numerical limits macros. cal limits The type of a bit-field is more than just the integer type used in its declaration. The width is also considered bit-field 1407 to be part of its type. This means that assignment, for instance, to a bit-field object may result in the value interpreted as being assigned having its value changed. 1 void DR_120(void) 2 { 3 struct { 4 unsigned int mem : 1; 5 } x; 6 /* 7 * The value 3 can be represented in an unsigned int, 8 * but is changed by the assignment in this case. 9 */ 10 x.mem = 3; 11 } C90 Support for the type _Bool is new in C99, and the C90 Standard did not need to include it as an exception. Other Languages This general statement holds true for conversions in other languages. v 1.2 June 24, 2009
  11. Signed and unsigned integers 684 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 480.1 object integer type. int type only 683 Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more unsigned integer than the maximum value that can be represented in the new type until the value is in the range of the new conversion to type.49) 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 largest number that can be represented in the unsigned integer type.28) 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 496 unsigned should be occurring in the first place. computation modulo reduced 684 Otherwise, the new type is signed and the value cannot be represented in it; integer value not represented Commentary in signed integer 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). June 24, 2009 v 1.2
  12. 686 Real floating and integer Coding Guidelines A guideline recommendation that the converted value always be representable might be thought to be equivalent to one requiring that a program not contain defects. However, while the standard may not specify an algorithm for this conversion, there is a commonly seen implementation behavior. Developers sometimes represen- 569.1 intentionally make use of this common behavior and the applicable guideline is the one dealing with the use tation in- of representation information. formation using signed inte- either the result is implementation-defined or an implementation-defined signal is raised. 685 ger conversion implementation- Commentary defined There is no universally agreed-on behavior (mathematical or processor) for the conversion of out-of-range 42 signed values, so the C Standard’s Committee could not simply define this behavior as being what happens in implementation- defined practice. The definition of implementation-defined behavior does not permit an implementation to raise a behavior signal; hence, the additional permission to raise a signal is specified here. C90 The specification in the C90 Standard did not explicitly specify that a signal might be raised. This is because the C90 definition of implementation-defined behavior did not rule out the possibility of an implementation raising a signal. The C99 wording does not permit this possibility, hence the additional permission given here. C++ . . . ; otherwise, the value is implementation-defined. 4.7p3 The C++ Standard follows the wording in C90 and does not explicitly permit a signal from being raised in this context because this behavior is considered to be within the permissible range of implementation-defined behaviors. Other Languages Languages vary in how they classify the behavior of a value not being representable in the destination type. Java specifies that all the unavailable significant bits (in the destination type) are discarded. Ada requires that an exception be raised. Other languages tend to fall between these two extremes. Common Implementations The quest for performance and simplicity means that few translators generate machine code to check for nonrepresentable conversions. The usual behavior is for the appropriate number of least significant bits from the original value to be treated as the converted value. The most significant bit of this new value is treated as a sign bit, which is sign-extended to fill the available space if the value is being held in a register. If the conversion occurs immediately before a store (i.e., a right-hand side value is converted before being assigned into the left hand side object), there is often no conversion; the appropriate number of value bits are simply written into storage. Some older processors[287] have the ability to raise a signal if a conversion operation on an integer value is not 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. Real floating and integer floating-point When a finite value of real floating type is converted to an integer type other than _Bool, the fractional part is 686 converted to discarded (i.e., the value is truncated toward zero). integer Commentary NaNs are not finite values and neither are they infinities. IEEE-754 6.3 v 1.2 June 24, 2009
  13. Real floating and integer 686 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 616 negative zero be a positive zero. only generated by C90 Support for the type _Bool is new in C99. Other Languages This behavior is common to most languages. Common Implementations Many processors include instructions that perform truncation when converting values of floating type to 352 an integer type. On some processors the rounding mode, which is usually set to round-to-nearest, has to 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 1328 integer con- An expression consisting of a cast of a floating constant to an integer type is an integer constant expression. stant expres- sion Such 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 to printf will occur. 1 #include 2 3 void f(void) 4 { 5 float fval = 123456789.0; 6 long lval = (long)123456789.0; 7 8 if (lval != (long)fval) 9 printf("(long)123456789.0 == %ld and %ld\n", lval, (long)fval); 10 } 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 .0 appended 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). Rev 686.1 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. June 24, 2009 v 1.2
  14. 687 Real floating and integer In the following example, a floating constant passed to CALC_1 results in glob being converted to a floating type. If the value of glob contains more significant digits than supported by the floating type, the final result assigned to loc will not be the value expected. Using explicit casts, as in CALC_2, removes the problem operand 653 convert au- tomatically caused by the macro argument having a floating type. However, as discussed elsewhere, other dependencies are introduced. Explicitly performing the cast, where the argument is passed, mimics the behavior of a function call and shows that the developer is aware of the type of the argument. 1 #define X_CONSTANT 123456789.0 2 #define Y_CONSTANT 2 3 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; 9 10 void f(void) 11 { 12 long loc; 13 14 loc = CALC_1(X_CONSTANT); 15 loc = CALC_1(Y_CONSTANT); 16 17 loc = CALC_2(X_CONSTANT); 18 loc = CALC_2(Y_CONSTANT); 19 20 loc = CALC_3((long)X_CONSTANT); 21 loc = CALC_3(Y_CONSTANT); 22 } 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 floating type. The costs and benefits of relying on implicit conversions or using explicit casts are discussed, in general, operand 653 convert au- tomatically elsewhere. That discussion did not reach a conclusion that resulted in a guideline recommendation being made. Literals differ from objects in that they are a single instance of a single value. As such developers have greater control over their use, on a case by case basis, and a guideline recommendation is considered to integer 835.2 be more worthwhile. This guideline recommendation is similar to the one given for conversions of suffixed constant with suffix, not integer constants. immediately converted Cg 686.2 A floating constant shall not be implicitly converted to an integer type. If the value of the integral part cannot be represented by the integer type, the behavior is undefined.50) 687 Commentary The exponent part in a floating-point representation allows very large values to be created, these could significantly exceed the representable range supported by any integer type. The behavior specified by the standard reflects both the fact that there is no commonly seen processor behavior in this case and the execution-time overhead of performing some defined behavior. Other Languages Other languages vary in their definition of behavior. Like integer values that are not representable in the destination type, some languages require an exception to be raise while others specify undefined behavior. In this case Java uses a two step-process. It first converts the real value to the most negative, or largest positive v 1.2 June 24, 2009
  15. Real floating and integer 688 (depending on the sign of the floating-point number) value representable in a long or an int. In the second step, if the converted integer type is not long or int; 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 Figure 687.1). Some DSP proces- arithmetic saturated sors[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 into 334 exponent account 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 684 integer value cannot be represented. However, a major difference is processor behavior. There is greater execution not 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. 688 When a value of integer type is converted to a real floating type, if the value being converted can be represented integer exactly in the new type, it is unchanged. conversion to floating 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_RADIX has a value of two, the most common case). As the power of two increases, the numeric distance 366 FLT_RADIX between representable values increases (see Figure 368.1). The value of the *_DIG macros specify the 369 *_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 representation FLT_DIG is six, which is less than the number of representable digits in an object having type long (or 32-bit int). 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] June 24, 2009 v 1.2
  16. 688 Real floating and integer C++ An rvalue of an integer type or of an enumeration type can be converted to an rvalue of a floating point type. The 4.9p2 result is exact if possible. Who decides what is possible or if it can be represented exactly? A friendly reading suggests that the meaning is the same as C99. Common Implementations The Unisys A Series[1422] uses the same representation for integer and floating-point types (an integer was a single precision value whose exponent was zero). Coding Guidelines A common, incorrect belief held by developers is that because floating numbers can represent a much larger range of values than integers and include information on fractional parts, they must be able to exactly represent the complete range of values supported by any integer type. What is overlooked is that the support for an exponent value comes at the cost of graininess in the representation for large value (if objects of integer and floating type are represented in the same number of value bits). The major conceptual difference between integer and floating types is that one is expected to hold an exact value and the other an approximate value. If developers are aware that approximations can begin at the point an integer value is converted, then it is possible for them to take this into account in designing algorithms. Developers who assume that inaccuracies don’t occur until the floating value is operated on are in for a surprise. Rev 688.1 Algorithms containing integer values that are converted to floating values shall be checked to ensure that any dependence on the accuracy of the conversion is documented and that any necessary execution-time checks against the *_DIG macros are made. floating 686.2 constant The rationale behind the guideline recommendations against converting floating constants to integer constants implicitly converted do not apply to conversions of integer constants to floating types. Example 1 #include 2 #include 3 4 static float max_short = (float)SHRT_MAX; 5 static float max_int = (float)INT_MAX; 6 static float max_long = (float)LONG_MAX; 7 8 int main(void) 9 { 10 float max_short_m1, 11 max_int_m1, 12 max_long_m1; 13 14 for (int i_f=1; i_f < 3; i_f++) 15 { 16 max_short_m1 = (float)(SHRT_MAX - i_f); 17 if (max_short == max_short_m1) 18 printf("float cannot represent all representable shorts\n"); 19 max_short=max_short_m1; 20 max_int_m1 = (float)(INT_MAX - i_f); 21 if (max_int == max_int_m1) 22 printf("float cannot represent all representable ints\n"); v 1.2 June 24, 2009
  17. Real floating and integer 690 23 max_int=max_int_m1; 24 max_long_m1 = (float)(LONG_MAX - i_f); 25 if (max_long == max_long_m1) 26 printf("float cannot represent all representable longs\n"); 27 max_long=max_long_m1; 28 } 29 } 689 If the value being converted is in the range of values that can be represented but cannot be represented exactly, int to float nearest repre- the result is either the nearest higher or nearest lower representable value, chosen in an implementation- sentable value defined manner. Commentary There is no generally accepted behavior in this situation. The standard leaves it up to the implementation. Other Languages Most languages are silent on this issue. Common Implementations Most processors contain a status flag that is used to control the rounding of all floating-point operations. 200 status flag floating-point Given that round-to-nearest is the most common rounding mode, the most likely implementation-defined 352 FLT_ROUNDS behavior is round-to-nearest. 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. 690 48) The integer promotions are applied only: as part of the usual arithmetic conversions, to certain argument footnote 48 expressions, to the operands of the unary +, -, and ~ operators, and to both operands of the shift operators, 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 a switch statement. 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. 1744 if statement The standard does not specify that the implicit test against zero, in an if statement or iteration statement, operand0compare against will cause a single object (forming the complete controlling expression) to be promoted. A promotion would 1766 iteration statement not affect the outcome in these contexts, and an implementation can use the as-if rule in selecting the best executed repeat- edly 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. June 24, 2009 v 1.2
  18. 692 Real floating and integer 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 are more likely to forget that the integer promotions occur (or invent mythical special cases where they don’t occur) rather than worry about additional conversions because of them. Coding guideline documents are no substitute for proper training. footnote 49) The rules describe arithmetic on the mathematical value, not the value of a given type of expression. 691 49 Commentary This means that there are no representational issues involving intermediate results being within range of the type of the values. The abstract machine must act as if the operation were performed using infinite precision arithmetic. C90 This observation was not made in the C90 Standard (but was deemed to be implicitly true). C++ The C++ Standard does not make this observation. footnote 50) The remaindering operation performed when a value of integer type is converted to unsigned type need 692 50 not be performed when a value of real floating type is converted to unsigned type. Commentary This permission reflects both differences in processor instruction behavior and the (in)ability to detect and catch those cases where the conversion might be performed in software. The behavior is essentially unspecified, although it is not explicitly specified as such (and it does not appear in the list of unspecified behaviors in annex J.1). C++ An rvalue of a floating point type can be converted to an rvalue of an integer type. The conversion truncates; that 4.9p1 is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination 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 signed integer 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 any integer type supported by an implementation requires that the processor conversion instruction either perform the remainder operation or raise some kind of range error signal that is caught by the implementation, which then performs the remainder operation in software. Coding Guidelines This is one area where developers’ expectations may not mirror the behavior that an implementation is required to support. Example The following program may, or may not, output the values given in the comments. v 1.2 June 24, 2009
  19. Real floating types 695 1 #include 2 #include 3 4 int main(void) 5 { 6 double d = UINT_MAX; 7 printf("%f, %u\n", d, (unsigned int)d); /* 4294967295.000000, 4294967295 */ 8 d += 42; 9 printf("%f, %u\n", d, (unsigned int)d); /* 4294967337.000000, 41 */ 10 d *= 20; 11 printf("%f, %u\n", d, (unsigned int)d); /* 85899346740.000000, 820 */ 12 d = -1; 13 printf("%f, %u\n", d, (unsigned int)d); /* -1.000000, 4294967295 */ 14 } 693 Thus, the range of portable real floating values is (−1, Utype_MAX + 1). Commentary 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. 694 If the value being converted is outside the range of values that can be represented, the behavior is undefined. Commentary An unsigned integer type represented in 123 bits, or more, could contain a value that would be outside the 373 range of values representable in a minimum requirements float type (128 bits would be needed to exceed *_MAX_10_EXP the range of the IEC 60559 single-precision). C++ Otherwise, it is an implementation-defined choice of either the next lower or higher representable value. 4.9p2 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. Real floating types 695 When a float is promoted to double or long double, or a double is promoted to long double, its value is float promoted to dou- unchanged (if the source value is represented in the precision and range of its type). ble or long double June 24, 2009 v 1.2
  20. 696 Real floating types Commentary Although not worded as such, this is a requirement on the implementation. The type double must have at least the same precision in the significand and at least as much range in the exponent as the type float, similarly for the types double and long double. A situation where the source value might not be represented in the precision and range of its type is when 354 FLT_EVAL_METHOD has a non-zero value. For instance, if FLT_EVAL_METHOD has a value of 2, then the value FLT_EVAL_METHOD 0.1f is represented to the precision of long double, while the type remains as float. If a cast to double is performed the value may be different to that obtained when FLT_EVAL_METHOD was zero. The wording was changed by the response to DR #318. C++ The type double provides at least as much precision as float, and the type long double provides at least as 3.9.1p8 much precision as double. The set of values of the type float is a subset of the set of values of the type double; the set of values of the type double is a subset of the set of values of the type long double. This only gives a relative ordering on the available precision. It does not say anything about promotion leaving a value unchanged. An rvalue of type float can be converted to an rvalue of type double. The value is unchanged. 4.6p1 There is no equivalent statement for type double to long double promotions. But there is a general statement about conversion of floating-point values: An rvalue of floating point type can be converted to an rvalue of another floating point type. If the source value 4.8p1 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 wider floating-point type (3.9.1p8); and (2) when a value is converted to the wider type, the exact representation is required 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 several different floating-point precisions and define mechanisms to allow developers to specify different floating types. While implementations that provide multiple floating-point types usually make use of the same processor hardware as that available to a C translator, other languages rarely contain this requirement. Common Implementations This requirement is supported by IEC 60559, where each representation is an extension of the previous ones holding less precision. double When a double is demoted to float, a long double is demoted to double or float, or a value being 696 demoted to an- other floating represented in greater precision and range than required by its semantic type (see is explicitly type converted to its semantic type (including to its own type), if the value being converted can be represented exactly in the new type, it is unchanged. Commentary A simple calculation would suggest that unless an implementation uses the same representation for floating- point types, the statistically likelihood of a demoted value being exactly representable in the new type would be very low (an IEC 60559 double-precision type contains 232 values that convert to the same single-precision value). However, measurements of floating-point values created during program execution binary * 1147 show a surprisingly high percentage of value reuse (these results are discussed elsewhere). result value 940 profiling A situation where a value might be represented in greater precision and range than required by its type is 354 FLT_EVAL_METHOD when FLT_EVAL_METHOD has a non-zero value. float 695 promoted to dou- ble or long double v 1.2 June 24, 2009
Đồng bộ tài khoản