C99 (superseded): issue log

This issue log has been automatically converted from the original issue lists and some formatting may not have been preserved.

Issue Summary Status
0201 Integer types longer than long Closed
0202 Change return type of certain <fenv.h> functions Fixed in C99 TC1
0203 C locale conflict with ISO/IEC 9945-2 Fixed in C99
0204 size_t and ptrdiff_t as a long long type Fixed in C99 TC1
0205 New keyword __at_least Closed
0206 Default argument conversion of float _Complex Closed
0207 Handling of imaginary types Fixed in C99 TC2
0208 Ambiguity in initialization Fixed in C99 TC1
0209 Problem implementing INTN_C macros Fixed in C99 TC1
0210 fprintf %a and %A conversions recommended practice Fixed in C99 TC1
0211 Accuracy of decimal string to/from "binary" (non-decimal) floating-point conversions Fixed in C99 TC2
0212 Binding of multibyte conversion state objects Closed
0213 Lacuna in mbrtowc Fixed in C99 TC1
0214 atexit function registration Closed
0215 Equality operators Fixed in C99 TC2
0216 Source character encodings Fixed in C99 TC1
0217 asctime limits Closed
0218 Signs of non-numeric floating point values Fixed in C99 TC2
0219 Effective types Closed
0220 Definition of "decimal integer" Fixed in C99 TC1
0221 Lacuna in pointer arithmetic Closed
0222 Partially initialized structures Fixed in C99 TC2
0223 FP_FAST_FMAF and FP_FAST_FMAL should be integer constant Fixed in C99 TC2
0224 fpclassify return is not defined Fixed in C99 TC2
0225 strtod, strtof and strtold expected form of the subject sequence Fixed in C99 TC2
0226 strftime references Closed
0227 strftime %U, %V, and %W conversion specifiers Closed
0228 wmemcmp declaration in Annex B Fixed in C99 TC1
0229 localeconv() *_sep_by_space table entries issues Fixed in C99 TC2
0230 Enumerated type rank Fixed in C99 TC2
0231 Semantics of text-line and non-directive Closed
0232 Typo in Annex I Fixed in C99 TC1
0233 %g, %G precision specification Fixed in C99 TC2
0234 Miscellaneous Typos Fixed in C99 TC1
0235 "C" locale collating behaviour not defined Closed
0236 The interpretation of type based aliasing rule when applied to union objects or allocated objects Closed
0237 Declarations using [static] Closed
0238 Decriptions of fma() overflow and underflow errors are missing Fixed in C99 TC2
0239 Annex F nexttoward description is inconsistent with 7.12.11.4. and F.9.8.3 Fixed in C99 TC2
0240 lrint, llrint, lround, llround, and ilogb descriptions are not consistent for unrepresentable results Fixed in C99 TC2
0241 Make the base standard and Annex F consistent for pow(0, <0) Fixed in C99 TC2
0242 Make the base standard and Annex F consistent for logb(0) Fixed in C99 TC2
0243 Make the base standard and Annex F consistent for fmod(), remainder(), and remquo() for a zero divisor Fixed in C99 TC2
0244 tgamma(zero or negative integer) should be considered a pole error Fixed in C99 TC2
0245 Missing paragraph numbers Fixed in C99 TC2
0246 completion of declarators Closed
0247 are values a form of behaviour ? Fixed in C99 TC2
0248 limits are required for optional types Fixed in C99 TC2
0249 Lacuna applying C89:TC1 to C99 Fixed in C99 TC2
0250 non-directives within macro arguments Fixed in C99 TC2
0251 are struct fred and union fred the same type ? Fixed in C99 TC3
0252 incomplete argument types when calling non-prototyped functions Fixed in C99 TC3
0253 "overriding" in designated initializers Closed
0254 mbtowc and partial characters Closed
0255 non-prototyped function calls and argument mismatches Closed
0256 multiple inclusion of headers Closed
0257 common initial sequences and related issues with unions Closed
0258 ordering of "defined" and macro replacement Closed
0259 macro invocations with no arguments Closed
0260 indeterminate values and identical representations Closed
0261 constant expressions Closed
0262 maximum size of bit fields Fixed in C99 TC2
0263 all-zero bits representations Fixed in C99 TC2
0264 graphic characters Closed
0265 preprocessor arithmetic Fixed in C99 TC2
0266 overflow of sizeof Closed
0267 Typos in 5.1.2.3, 7.24.4.4.5, 7.24.6.1, 7.24.6.1 Fixed in C99 TC2
0268 jumps into iteration statements Fixed in C99 TC3
0269 lacunae in exact-width integer types Fixed in C99 TC2
0270 wint_t is not the promoted version of wchar_t Fixed in C99 TC2
0271 lacuna in iswctype and towctrans Closed
0272 type category Fixed in C99 TC2
0273 meaning of __STDC_ISO_10646__ Fixed in C99 TC2
0274 meaning of "character" in <string,h> functions Fixed in C99 TC2
0275 bitwise-OR of nothing Fixed in C99 TC2
0276 orientation of perror Fixed in C99 TC2
0277 declarations within iteration statements Closed
0278 lacuna in character encodings Fixed in C99 TC2
0279 Wide character code values for members of the basic character set Fixed in C99 TC2
0280 struct tm, member tm_isdst, and mktime() in <time.h> Closed
0281 CLOCKS_PER_SEC should not be a constant expression Fixed in C99 TC2
0282 flexible array members & struct padding Fixed in C99 TC2
0283 Accessing a non-current union member ("type punning") Fixed in C99 TC3
0284 Does <math.h> define INT_MIN and INT_MAX? Closed
0285 Conversion of an imaginary type to _Bool Fixed in C99 TC2
0286 Correctly rounded and rounding direction/mode Fixed in C99 TC3
0287 Floating-point status flags and sequence points Fixed in C99 TC3
0288 deficiency on multibyte conversions Closed
0289 Function prototype with [restrict] Fixed in C99 TC3
0290 FLT_EVAL_METHOD and extra precision and/or range Fixed in C99 TC3
0291 corrections to requirements on inexact floating-point exceptions Fixed in C99 TC3
0292 Use of the word variable Fixed in C99 TC3
0293 Typo in Standard - double complex instead of complex in an example Fixed in C99 TC3
0294 Technical question on C99 restrict keyword Closed
0295 Incomplete types for function parameters Fixed in C99 TC3
0296 Is exp(INFINITY) overflow? A range error? A divide-by-zero exception? INFINITY without any errors? Fixed in C99 TC3
0297 May FE_* floating-point exception flags have bits in common? Fixed in C99 TC3
0298 Validity of constant in unsigned long long range Fixed in C99 TC3
0299 Is cabs() a type-generic macro? Fixed in C99 TC3
0300 Translation-time expresssion evaluation Closed
0301 Meaning of FE_* macros in <fenv.h> Closed
0302 6.10.2p5: Adding underscore to portable include file name character set Fixed in C99 TC3
0303 6.10p2: Breaking up the very long sentence describing preprocessing directive Fixed in C99 TC3
0304 Clarifying illegal tokens in #if directives Fixed in C99 TC3
0305 6.10.1p3: Clarifying handling of keywords in #if directives Fixed in C99 TC3
0306 6.10.3p9: Clarifying that rescanning applies to object-like macros Fixed in C99 TC3
0307 6.10.3p10: Clarifiying arguments vs. parameters Fixed in C99 TC3
0308 Clarify that source files et al. need not be "files" Fixed in C99 TC3
0309 Clarifying trigraph substitution Fixed in C99 TC3
0310 Add non-corner case example of trigraphs Fixed in C99 TC3
0311 Definition of variably modified types Fixed in C99 TC3
0312 Meaning of "known constant size" Fixed in C99 TC3
0313 Incomplete arrays of VLAs Closed
0314 Cross-translation-unit tagged type compatibility Closed
0315 Implementation-defined bit-field types Fixed in C11
0316 Unprototyped function types Closed
0317 Function definitions with empty parentheses Closed
0318 (double)0.1f with FLT_EVAL_METHOD being 2 Fixed in C99 TC3
0319 printf("%a", 1.0) and trailing zeros Closed
0320 Scope of variably modified type Fixed in C99 TC3
0321 Wide character code values for members of the basic character set Fixed in C99 TC3
0322 Problem with TC2 Change #67 (Add perror to the list defining byte input/output functions.) Fixed in C99 TC3
0323 Potential problems with TC2 #34, #35, and #36 Fixed in C99 TC3
0324 Tokenization obscurities Fixed in C99 TC3
0325 strerror() Closed
0326 asctime() Fixed in C11
0327 Italicize definition of variable length array type, add forward references Fixed in C11
0328 String literals in compound literal initialization Fixed in C11
0329 Math functions and directed rounding Fixed in C11
0330 Externally visible exceptional conditions Fixed in C11
0331 permit FE_DIVBYZERO when errno says EDOM Closed
0332 gets is generally unsafe Fixed in C99 TC3
0333 Missing Predefined Macro Name Fixed in C99 TC3
0334 Missing semantics of comparison macros Closed
0335 _Bool bit-fields Closed
0336 TMP_MAX Fixed in C11
0337 stdio.h macro definition problems Closed
0338 C99 seems to exclude indeterminate value from being an uninitialized register Fixed in C11
0339 Variably modified compound literals Fixed in C11
0340 Composite types for variable-length arrays Fixed in C11
0341 [*] in abstract declarators Fixed in C11
0342 VLAs and conditional expressions Fixed in C11
0343 Initializing qualified wchar_t arrays Fixed in C11
0344 Casts in preprocessor conditional expressions Fixed in C11
0345 Where does parameter scope start? Fixed in C11

Issue 0201: Integer types longer than long

Authors: Clive Feather (UK)
Date: 1999-07-06
Reference document: ISO/IEC WG14 N883
Status: Closed
Converted from: summary-c99.htm, dr_201.htm

Summary

Require that size_t be no wider than unsigned long and ptrdiff_t be no wider than signed long.

Urgency
If this change is not made now, there will be a window of opportunity - of at least two years - when implementations can make size_t be wider than unsigned long. By the time any future Amendment is ready it will be impractical to re-impose the restriction. If the change is made now, it can always be relaxed if it becomes necessary.

Rationale
Various types in the Standard are defined as integer types. Two of these size_t and ptrdiff_t - are frequently manipulated and on many implementations need to hold values of the same order as [un]signed long. In C89 there are various programming idioms that involve these types but also need a standard integer type. For example:

printf ("%lu", (unsigned long) sizeof X);

or:

int *P1, *P2;
... /* make P1 and P2 point into the same array*/
malloc (sizeof (int) * labs (P1 - P2));

If these types are allowed to become wider than long, these idioms will stop working. More importantly, this might not happen when the code is compiled but rather when large values first get used by a previously working program. This is clearly a Quiet Change.

There do not appear to be any implementations which would be affected by this proposal, and it eliminates the vast majority of potential problems with these two types. While there are other types that theoretically meet these criteria, such as sig_atomic_t, in practice they are unlikely to be larger than long and no action is needed. There are also types in POSIX and other standards, such as off_t, which are similarly affected, but they are outside the scope of C9X; the recommended practice section would assist them.

Suggested Technical Corrigendum

Append a new paragraph to 7.18.3:

The value of SIZE_MAX shall be no greater than that of ULONG_MAX. The absolute values of PTRDIFF_MIN and PTRDIFF_MAX shall be no greater than those of LONG_MIN andLONG_MAX respectively.

or change the first part of 7.17 paragraph 2 to:

[#2] The types are ptrdiff_t which is the signed integer type of the result of subtracting two pointers (the width of ptrdiff_t shall be no greater than that of signed long);

size_t

which is the unsigned integer type of the result of the sizeof operator (the width of size_t shall be no greater than that of unsigned long); or both (the changes are equivalent in effect).

Possibly also add the following paragraph somewhere (perhaps in 6.3.1.3):

Recommended practice

Implementations should provide a mode which will warn of conversions (including those involving an explicit cast) where:

(Headers provided by the implementation are not limited to those defined by this Standard, but explicitly excludes <stdint.h>.)


Comment from WG14 on 2007-09-06:

Committee Response

There is no consensus to make this change or any change along this line.



Issue 0202: Change return type of certain <fenv.h> functions

Authors: Clive Feather (UK)
Date: 1999-07-06
Reference document: ISO/IEC WG14 N883
Status: Fixed
Fixed in: C99 TC1
Converted from: summary-c99.htm, dr_202.htm

Summary

Change the return type of various functions in 7.6.2 from void to int so that they can fail.

Urgency
These functions are new in C99. Once the function prototypes have been published it will not be practical to change them. The only solution will be to produce new parallel functions with a return value; because of the way these functions are defined, this will involve significantly more change than just that.

Rationale
The functions in question are to do with the floating-point exception and environment flags. The former will do as an example.

The wording of the FDIS assumes that either:

In the first case it defines various FE_ macros such as FE_DIVBYZERO for the flags. The Standard then assumes that it is always possible to set or clear the flag or to raise the exception. In the second case the macros are not defined and so there are no valid argument values for the functions (other than zero).

However, there are implementations that can do some things with the flags but not others. For example, it may be possible to raise exceptions but not to clear flags. This case is not allowed in the present draft.

The two alternative proposed changes are:

  1. Change the return types of the functions to int. For now the functions always return zero (success) but a later Amendment can alter this. This is the minimum to "future-proof".
  2. Change the definitions properly to allow them to fail. This is more complex but solves the problem once and for all.

Option 2 contains an extra item to makefesetround more consistent with the other changes. This change may be omitted if it will increase consensus.

Proposed solutions
Option A
- placeholder change

For each of the following functions:

feclearexcept
fegetexceptflag
feraiseexcept
fesetexceptflag
fegetenv
fesetenv
feupdateenv

change the return type to int and add the following:

Returns

This function always returns zero. [*]

[*] This may change in a future revision of this Standard, in which case a zero return will mean success and a non-zero return will mean failure of some kind.

Add to the Future Directions clause:

The fact that various functions in 7.6.2 and 7.6.4 always return zero is an obsolescent feature.

Option B - full change

In 7.6 paragraph 5, attach a footnote to the wording:

if and only if the implementation supports the floating-point exception by means of the functions in 7.6.2.

where the footnote is:

[*] The implementation supports an exception if there are circumstances where a call to at least one of the functions in 7.6.2, using the macro as the appropriate argument, will succeed. It is not necessary for all the functions to succeed all the time.

For each of the following functions:

feclearexcept
fegetexceptflag
feraiseexcept
fesetexceptflag
fegetenv
fesetenv
feupdateenv

make changes equivalent to the following (which shows the wording changes for 7.6.2.1).

In paragraph 2, replace "clears" with "attempt to clear".

Add a new heading and paragraph 3:

Returns

[3] The feclearexcept function returns zero if the excepts argument is zero or if all the specified exceptions were successfully cleared. Otherwise it returns a nonzero value.

Optional additional change: replace 7.6.3.2p3 by:

[3] The fesetround function returns zero if and only if the requested rounding direction was established.


Comment from WG14 on 2001-01-22:

Technical Corrigendum

In 7.6 paragraph 5, attach a footnote to the wording:

if and only if the implementation supports the floating-point exception by means of the functions in 7.6.2.

where the footnote is:

[*] The implementation supports an exception if there are circumstances where a call to at least one of the functions in 7.6.2, using the macro as the appropriate argument, will succeed. It is not necessary for all the functions to succeed all the time.

In 7.6.2.1 paragraph 1, change the result type from void to int.

In 7.6.2.1 paragraph 2, replace "clears" with "attempts to clear".

In 7.6.2.1 add a new heading and paragraph 3:

Returns

[#3] The feclearexcept function returns zero if the excepts argument is zero or if all the specified exceptions were successfully cleared. Otherwise it returns a nonzero value.

In 7.6.2.2 paragraph 1, change the result type from void to int.

In 7.6.2.2 paragraph 2, replace "stores" with "attempts to store".

In 7.6.2.2 add a new heading and paragraph 3:

Returns

[#3] The fegetexceptflag function returns zero if the representation was successfully stored. Otherwise it returns a nonzero value.

In 7.6.2.3 paragraph 1, change the result type from void to int.

In 7.6.2.3 paragraph 2, replace "raises" with "attempts to raise".

In 7.6.2.3 add a new heading and paragraph 3:

Returns

[#3] The feraiseexcept function returns zero if the excepts argument is zero or if all the specified exceptions were successfully raised. Otherwise it returns a nonzero value.

In 7.6.2.4 paragraph 1, change the result type from void to int.

In 7.6.2.4 paragraph 2, replace "sets" with "attempts to set".

In 7.6.2.4 add a new heading and paragraph 3:

Returns

[#3] The fesetexceptflag function returns zero if the excepts argument is zero or if all the specified flags were successfully set to the appropriate state. Otherwise it returns a nonzero value.

In 7.6.3.2 replace paragraph 3 by:

[#3] The fesetround function returns zero if and only if the requested rounding direction was established.

In 7.6.4.1 paragraph 1, change the result type from void to int.

In 7.6.4.1 paragraph 2, replace "stores" with "attempts to store".

In 7.6.4.1 add a new heading and paragraph 3:

Returns

[#3] The fegetenv function returns zero if representation was successfully stored. Otherwise it returns a nonzero value.

In 7.6.4.3 paragraph 1, change the result type from void to int.

In 7.6.4.3 paragraph 2, replace "establishes" with "attempts to establish".

In 7.6.4.3 add a new heading and paragraph 3:

Returns

[#3] The fesetenv function returns zero if the environment was successfully established. Otherwise it returns a nonzero value.

In 7.6.4.4 paragraph 1, change the result type from void to int.

In 7.6.4.4 paragraph 2, replace "saves" with "attempts to save", replace "installs" by "install", and replace "raises" by "raise".

In 7.6.4.4 add a new heading and paragraph 3:

Returns

[#3] The feupdateenv function returns zero if all the actions were successfully carried out. Otherwise it returns a nonzero value.

In 7.6.4.4 change to existing paragraph 3, also renumbering it as 4:

[#3] EXAMPLE Hide spurious underflow floating-point exceptions:

       #include <fenv.h>
         double f(double x)
         {
             #pragma STDC FENV_ACCESS ON
             double result;
             fenv_t save_env;
             if (feholdexcept(&save_env))
                 return /* indication of an environmental problem*/;
             // compute result           if (/* test spurious underflow*/)
                 if (feclearexcept(FE_UNDERFLOW))
                     return /* indication of an environmental problem */;
             if (feupdateenv(&save_env))
                 return /* indication of an environmental problem*/;
             return result;
         }

In Annex B change the return types for the following to int.

feclearexcept
fegetexceptflag
feraiseexcept
fesetexceptflag
fegetenv
fesetenv
feupdateenv


Issue 0203: C locale conflict with ISO/IEC 9945-2

Authors: WG15, Project Editor (Larry Jones)
Date: 1999-08-18
Reference document: ISO/IEC WG14 N888
Status: Fixed
Fixed in: C99
Converted from: summary-c99.htm, dr_203.htm

Summary

In subclause 7.23.3.5p7, the specifications for the strftime %c, %p, and%x conversion specifiers in the C locale conflict with the specifications in ISO/IEC 9945-2 for the POSIX locale.  As the POSIX and C locales have always been intended to be compatible, we strongly suggest changing these specifications to match the pre-existing POSIX specifications.

Suggested Correction

In subclause 7.23.3.5, paragraph 7, page 345, change the definitions of %c, %p, and %x to:

%c

equivalent to "%a %b %e %T %Y".

%p

one of "AM" or "PM".

%x

equivalent to "%m/%d/%y".


Comment from WG14 on 2000-04-18:

Committee Response

Changes were incorporated into the Standard just before printing. This was considered an editorial change by the Committee.



Issue 0204: size_t and ptrdiff_t as a long long type

Authors: Canada C Working Group, Raymond Mak (Canada C Working Group)
Date: 1999-09-15
Reference document: ISO/IEC WG14 N893
Status: Fixed
Fixed in: C99 TC1
Converted from: summary-c99.htm, dr_204.htm

Summary

size_t and ptrdiff_t can now be a long long type, which is not necessary for hardwares that do not support 64-bit addressing. Implementors should be encouraged to choose a type for these two that minimizes compatibility problems to existing (32-bit) code.

Suggested Correction

In 7.17 at the end of p2, add the following:

Recommended Practice

The long long type should be used only if no other integer types can represent the value range required by the implementation.


Comment from WG14 on 2000-11-02:

Technical Corrigendum

Add to the end of 7.17:

Recommended Practice

[#4] The types used for size_t and ptrdiff_t should not have an integer conversion rank greater than that of signed long unless the implementation supports objects large enough to make this necessary.



Issue 0205: New keyword __at_least

Authors: Canada C Working Group, Raymond Mak (Canada C Working Group)
Date: 1999-09-15
Reference document: ISO/IEC WG14 N893
Status: Closed
Converted from: summary-c99.htm, dr_205.htm

Summary

6.7.5 introduces a new use of the static keyword. A new keyword should be used instead.

This use of static can only occur in function parameter declaration. If we examine the syntax carefully, static assignment-expression taken together inside [ and ] really plays the role of a type qualifier qualifying a pointer. This means the assignment-expression should only be allowed to follow immediately after the keyword static (when static is present), with no other type qualifiers allowed in between. Also, a new keyword should be used to make the meaning clear.

Suggested Correction

Use a new keyword, __at_least, in place of static.

Change 6.4.1p1 to add a new keyword: __at_least

Change the syntax under 6.7.5 to (the two occurrences of static to __at_least):

direct_declarator :
identifier
( declarator )
direct-declarator [ type-qualifier-listopt assignment-expressionopt ]
direct-declarator [ __at_least assignment-expression type-qualifier-listopt ]
direct-declarator [ type-qualifier-listopt __at_least assignment-expression ]
... (the rest is the same as in the FDIS) ...

Change 6.7.5.2p1 to (i.e. the two occurrences of static to __at_least):

[#1] In addition to optional type qualifiers and the keyword __at_least, the [ and ] may delimit an expression or *. If they delimit an expression (which specifies the size of an array), the expression shall have an integer type. If the expression is a constant expression, it shall have a value greater than zero. The element type shall not be an incomplete or function type. The optional type qualifiers and the keyword __at_least shall appear only in a declaration of a function parameter with an array type, and then only in the outermost array type derivation.

Change 6.7.5.2p3 to (i.e. the three occurrences of static to __at_least, and bind __at_least with assignment-expr in the syntax):

D[ type-qualifier-listopt assignment-expropt ]
D[ __at_least assignment-expr type-qualifier-listopt ]
D[ type-qualifier-list __at_least assignment-expr ]
D[ type-qualifier-listopt * ]

and the type specified for ident in the declaration "T D" is "derived-declarator-type-list T", then the type specified for ident is "derived-declarator-type-list array of T".121) (See 6.7.5.3 for the meaning of the optional type qualifiers and the keyword __at_least.)

Change 6.7.5.3p7 to (i.e. static to __at_least):

[#7] A declaration of a parameter as "array of type" shall be adjusted to "qualified pointer to type", where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. If the keyword __at_least ...

Change 6.7.5.3p21 to (i.e. static to __at_least):

[#21] EXAMPLE 5 The following are all compatible function prototype declarators.

       double maximum(int n, int m, double a[n][m]);
        double maximum(int n, int m, double a[*][*]);
        double maximum(int n, int m, double a[ ][*]);
        double maximum(int n, int m, double a[ ][m]);

as are:

       void f(double (* restrict a)[5]);
        void f(double a[restrict][5]);
        void f(double a[restrict 3][5]);
        void f(double a[restrict __at_least 3][5]);
        ...

Change A.1.2 to add keyword:

__at_least

Explanation of the change
The new syntax groups '__at_least assignment-expression' together. For example:

double a[restrict __at_least 3] /* ok */
double a[__at_least 3 restrict] /* ok */
double a[__at_least restrict 3] /*not ok */

Conceptually, '__at_least assignment-expression' is a type qualifier. Even though we do not treat it as such in C9X, the potential is there for future enhancement of the language. Therefore we should not interfere with possible future changes in this respect. The following example illustrates the point.

In a function parameter declaration, a parameter of "array of type" is adjusted to "qualified pointer to type". The type-qualifiers inside [ and ] become the qualifier for the pointer. If '__at_leastassignment-expression' is also a type qualifier, this adjustment enables us to write:

int * __at_least(10) p;

which declares a pointer pointing to the first of a sequence of 10 integers in memory. (The parentheses are used for clarity.) The clumsy description in 6.7.5.3p7 become unnecessary. Note that the current static syntax prevents us from writing the equivalent pointer declaration for an array parameter declaration.

This example is presented here only as an illustration of what is possible in the future; it is not meant as a suggested change for this DR. Nevertheless, it does show that allowing other qualifiers appearing between static and the assignment-expression is a conceptual error.


Comment from WG14 on 2001-09-18:

Committee Discussion

The committee has had several viewpoints on this controversial item. These are ranked with the choice getting the most support first, the last entry getting little or no support.

  1. Do nothing.

  2. Remove this feature (the use of static to mean a minimum array size).

  3. Deprecate this feature (the use of static to mean a minimum array size).

  4. In 6.7.5 Declarators (p. 114) and its subclauses, deprecate:

    direct-declarator [ static type-qualifier-listopt assignment-expression ]

    and change:

    direct-declarator [ type-qualifier-list static assignment-expression ]

    to:

    direct-declarator [ type-qualifier-listopt static assignment-expression ]

  5. Accept the suggestions of this DR.

Note:

There was a unanimous vote that the feature is ugly, and a good consensus that its incorporation into the standard at the 11th hour was an unfortunate decision.


Comment from WG14 on 2001-09-18:

Committee Response

There is no consensus to make this change or any change along this line.



Issue 0206: Default argument conversion of float _Complex

Authors: Clive Feather (UK)
Date: 1999-09-13
Reference document: ISO/IEC WG14 N892
Status: Closed
Converted from: summary-c99.htm, dr_206.htm

Summary

For consistency with real floating types, the type float _Complex should be promoted by the default argument promotions to double _Complex.

Suggested Technical Corrigendum

Change 6.5.2.2p6 in part, from:

and arguments that have type float are promoted to double.

to:

and arguments that have a corresponding real type of float are promoted, without change of type domain, to a type whose corresponding real type is double.


Comment from WG14 on 2001-09-18:

Committee Response

This was intentional because real float promotion to double is in Standard C purely for compatibility with K&R. Since complex is new, that compatibility is not an issue, and having it behave like real float would introduce undesired overhead (and be less like Fortran).

The following words were added the Rationale.

float _Complex is a new type with C99. It has no need to preserve promotions needed by pre-ANSI-C. It does not break existing code.



Issue 0207: Handling of imaginary types

Authors: Clive Feather (UK)
Date: 1999-06-27
Reference document: ISO/IEC WG14 N892
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_207.htm

Summary

The handling of imaginary types in the Standard is somewhat inconsistent. For example, they are not mentioned at all in 6.2.5 (other than a footnote), but are treated as first-class types in 6.7.2. Annex G makes certain assumptions about such types but these assumptions are not supported by the Standard.

Details

There are two reasonable approaches that could be followed. The first is to remove all mention of imaginary types from the main text of the Standard and put them all in Annex G. The second is to make the basic properties of imaginary types part of the main language (while still making them optional), leaving Annex G to handle the details of ISO 60559 imaginary types.

After some thought, the author of this DR feels that imaginary types are experimental enough that the first approach is better and has worded the Suggested Technical Corrigendum on that basis.

The keyword _Imaginary is mentioned in 6.4.1, 6.7.2, and 7.3.1. These references - and any related text - are all to be removed and replacement wording added to Annex G.

A new subclause G.4.4 is added. This specifies the practical implications of giving imaginary types the same representation and alignment as real floating types.

Suggested Technical Corrigendum

Delete "_Imaginary" from the list of keywords in 6.4.1. If this is felt to be too radical, instead add the following text to paragraph 2:

The keyword _Imaginary is not used in the C language, but is reserved for specifying imaginary types such as described in Annex G.

Delete "_Imaginary" from 6.7.2p1 and the three imaginary cases from 6.7.2p2.

Change 6.7.2p3 to read:

The type specifier _Complex shall not be used if the implementation does not provide complex types.

Delete 7.3.1p3.

Delete "imaginary" from 7.3.1p5.

Replace 7.3.1p4 with:

The macro I expands to _Complex_I.

Add a new paragraph before G.2p1:

There is a new keyword _Imaginary used to specify imaginary types. It is used as a type-specifier within declaration-specifiers in the same way as _Complex is (thus "_Imaginary float" is a valid type name).

Add a new subclause G.4.4

G.4.4 Interchangeable values

Though imaginary types are not compatible with the corresponding real type, values of one may be used where the other is expected in the following cases. In each case the value is converted to the value of the other type that has the same representation (that is, by multiplying by the imaginary unit when converting to an imaginary type, and by dividing by the imaginary unit when converting to a real type).

[*] If a prototype is in scope, conversion is as if by assignment and the value will be converted to zero.

Replace G.6p1 with:

The macros

imaginary

and

_Imaginary_I

are defined, respectively, as _Imaginary and a constant expression of type const float _Imaginary with the value of the imaginary unit. The macro I is defined to be _Imaginary_I (not _Complex_I as stated in 7.3). Notwithstanding the provisions of 7.1.3, a program may undefine and then perhaps redefine the macro imaginary.

Afternote
If WG14 wishes to take the alternative approach of moving _Imaginary types more firmly into the body of the Standard, then the following areas would be affected.


Comment from WG14 on 2001-09-18:

Technical Corrigendum:

In 6.4.1 append to paragraph 2:

The keyword _Imaginary is reserved for specifying imaginary types.footnote

footnoteOne possible specification for imaginary types is Annex G.

In 6.7.2 delete "_Imaginary" from paragraph 1, delete the cases:

from paragraph 2, and change paragraph 3 to read:

[#3] The type specifier _Complex shall not be used if the implementation does not provide complex types.101

Change footnote 101 to read:

101Freestanding implementations are not required to provide complex types.

In 7.3.1 replace paragraphs 3 to 5 with:

[#3] The macro

I

expands to _Complex_I.162

[#4] Notwithstanding the provisions of subclause 7.1.3, a program may undefine and perhaps then redefine the macros complex and I.

Add a new paragraph to the start of G.2:

[#0] There is a new keyword _Imaginary, which is used to specify imaginary types. It is used as a type-specifier within declaration-specifiers in the same way as _Complex is (thus "_Imaginary float" is a valid type name).

Replace G.6 paragraph 1 with:

[#1] The macro

imaginary

and

_Imaginary_I

are defined, respectively, as _Imaginary and a constant expression of type const float _Imaginary with the value of the imaginary unit. The macro

I

is defined to be _Imaginary_I (not _Complex_I as stated in 7.3). Notwithstanding the provisions of 7.1.3, a program may undefine and then perhaps redefine the macro imaginary.



Issue 0208: Ambiguity in initialization

Authors: Clive Feather (UK)
Date: 1999-09-06
Reference document: ISO/IEC WG14 N892
Status: Fixed
Fixed in: C99 TC1
Converted from: summary-c99.htm, dr_208.htm

Summary

When there is more than one initializer for the same object it is not clear whether both initializers are actually evaluated. Wording changes are proposed to clarify this.

Details

Subclause 6.7.8 paragraph 19 reads:

The initialization shall occur in initializer list order, each initializer provided for a particular subobject overriding any previously listed initializer for the same subobject; all subobjects that are not initialized explicitly shall be initialized implicitly the same as objects that have static storage duration.

Paragraph 23 reads:

The order in which any side effects occur among the initialization list expressions is unspecified.

If the same object is initialized twice, as in:

int a [2] = { f (0), f (1), [0] = f (2) };

the term "overriding" could be taken to mean that the first initializer is ignored completely, or it could be taken to mean that the expression is evaluated and then discarded. The proposed wording change assumes the latter.

Suggested Technical Corrigendum

Replace 6.7.8 paragraph 23 with:

All the initialization list expressions are evaluated, even if the resulting value will be overridden, but the order in which any side effects occur is unspecified.


Comment from WG14 on 2000-11-02:

Committee Response

The question asks about the expression

int a [2] = { f (0), f (1), [0] = f (2) };

and the meaning of the wording

each initializer provided for a particular subobject overriding any previously listed initializer for the same subobject;

It was the intention of WG14 that the call f(0) might, but need not, be made when a is initialized. If the call is made, the order in which f(0) and f(2) occur is unspecified (as is the order in which f(1) occurs relative to both of these). Whether or not the call is made, the result of f(2) is used to initialize a[0].

The wording of paragraph 23:

The order in which any side effects occur among the initialization list expressions is unspecified.

should be taken to only apply to those side effects which actually occur.

Technical Corrigendum

In 6.7.8 paragraph 19, attach a footnote to "the same subobject":

[*] Any initializer for the subobject which is overridden and so not used to initialize that subobject might not be evaluated at all.



Issue 0209: Problem implementing INTN_C macros

Authors: Douglas A. Gwyn (J11)
Date: 1999-10-19
Reference document: ISO/IEC WG14 N896
Status: Fixed
Fixed in: C99 TC1
Converted from: summary-c99.htm, dr_209.htm

Summary

The requirements of subclause 7.18.4.1 may be impossible to satisfy (for N = 8 or 16, typically) unless an implementation has special (non-standard) support for integer constants of types char and short:

The macro INTN_C(value ) shall expand to a signed integer constant with the specified value and type int_leastN_t.

(Similarly for UINTN_C.) The paragraph preceding this overly restrictive specification reflects the actual intent:

... a type with at least the specified width.

Possible Solutions

  1. Change "integer constant" to "integer constant expression". While this still does not reflect the original intent, at least it permits accurate implementation without special support from the compiler.
  2. Specify that the type shall be the promoted type corresponding to int_leastN_t.
  3. Specify that the type shall be any appropriately signed integer type of sufficient width.

Suggested Technical Correction
In subclause 7.18.4.1 paragraph 2, change the two occurrences of "and type" to "and [un]signed integer type at least as wide as".


Comment from WG14 on 2000-11-02:

Technical Corrigendum

7.18.4 Macros for integer constants

[#1] The following function-like macros220 expand to integer constant expressions suitable for initializing objects that have integer types corresponding to types defined in <stdint.h>. Each macro name corresponds to a similar type name in 7.18.1.2 or 7.18.1.5.

[#2] The argument in any instance of these macros shall be a decimal, octal, or hexadecimal constant (as defined in 6.4.4.1) with a value that does not exceed the limits for the corresponding type.

Add:

[#3] Each invocation of one of these macros shall expand to an integer constant expression suitable for use in #if preprocessing directives. The type of the expression shall have the same type as would an expression that is an object of the corresponding type converted according to the integer promotions. The value of the expression shall be that of the argument.

Most of the following wording is taken almost exactly from <limits.h>

7.18.4.1 Macros for minimum-width integer constants

Remove:

[#1] Each of the following macros expands to an integer constant having the value specified by its argument and a type with at least the specified width.221)

221 For each name described in 7.18.1.2 that the implementation provides, the corresponding macro in this subclause is required.

Change [#2] to:

[#2] The macro INTN_C(value ) shall expand to an integer constant expression corresponding to the type int_leastN_t. The macro UINTN_C(value ) shall expand to an integer constant expression corresponding to the type uint_leastN_t. For example, if uint_least64_t is a name for the type unsigned long long int, then UINT64_C(0x123) might expand to the integer constant 0x123ULL.

7.18.4.2 Macros for greatest-width integer constants

[#1] The following macro expands to an integer constant expression having the value specified by its argument and the type intmax_t:

INTMAX_C(value)

The following macro expands to an integer constant expression having the value specified by its argument and the type uintmax_t:

UINTMAX_C(value)



Issue 0210: fprintf %a and %A conversions recommended practice

Authors: WG 14, Fred Tydeman (US)
Date: 1999-10-20
Status: Fixed
Fixed in: C99 TC1
Converted from: summary-c99.htm, dr_210.htm

Summary

What should fprintf do when it is printing a floating-point number using %a and %A conversions and it is exactly representable in the given precision? That is, what is the result of: fprintf("%a", 1.0);? The current wording appears to say that it be converted into either 0x1.0p0+DBL_EPSILON or 0x1.0p0-DBL_EPSILON/FLT_RADIX, instead of the correct value 0x1.0p0 (this appears to be an oversight that forgot about exactly representable values).

What should the strtod family of functions do when converting a hexadecimal form of input and the result is exactly representable? That is, what is the result of: strtod("0x1.0p0", (char **)NULL);? The current wording appears to say that it be converted into either 1.0+DBL_EPSILON or 1.0-DBL_EPSILON/FLT_RADIX, instead of the correct value 1.0 (this appears to be an oversight that forgot about exactly representable values).


Comment from WG14 on 2001-01-22:

Technical Corrigendum

7.19.6.1 The fprintf function:

Page 279, Paragraph 12 should be changed from:

If FLT_RADIX is not a power of 2, the result should be one of the two adjacent numbers in hexadecimal floating style with the given precision, with the extra stipulation that the error should have a correct sign for the current rounding direction.

to:

For a and A conversions, if FLT_RADIX is not a power of 2 and the result is not exactly representable in the given precision, the result should be one of the two adjacent numbers in hexadecimal floating style with the given precision, with the extra stipulation that the error should have a correct sign for the current rounding direction.

7.20.1.3 The strtod ... functions:

Page 308, paragraph 8 should be changed from:

If the subject sequence has the hexadecimal form and FLT_RADIX is not a power of 2, the result should be one of the two numbers in the appropriate internal format that are adjacent to the hexadecimal floating source value, with the extra stipulation that the error should have a correct sign for the current rounding direction.

to:

If the subject sequence has the hexadecimal form, FLT_RADIX is not a power of 2 and the result is not exactly representable, the result should be one of the two numbers in the appropriate internal format that are adjacent to the hexadecimal floating source value, with the extra stipulation that the error should have a correct sign for the current rounding direction.

7.24.2.1 The fwprintf function:

Page 354, Paragraph 12 should be changed from:

If FLT_RADIX is not a power of 2, the result should be one of the two adjacent numbers in hexadecimal floating style with the given precision, with the extra stipulation that the error should have a correct sign for the current rounding direction.

to:

For a and A conversions, if FLT_RADIX is not a power of 2 and the result is not exactly representable in the given precision, the result should be one of the two adjacent numbers in hexadecimal floating style with the given precision, with the extra stipulation that the error should have a correct sign for the current rounding direction.

7.24.4.1.1 The wcstod ... functions:

Page 372, paragraph 8 should be changed from:

If the subject sequence has the hexadecimal form and FLT_RADIX is not a power of 2, the result should be one of the two numbers in the appropriate internal format that are adjacent to the hexadecimal floating source value, with the extra stipulation that the error should have a correct sign for the current rounding direction.

to:

If the subject sequence has the hexadecimal form, FLT_RADIX is not a power of 2 and the result is not exactly representable, the result should be one of the two numbers in the appropriate internal format that are adjacent to the hexadecimal floating source value, with the extra stipulation that the error should have a correct sign for the current rounding direction.



Issue 0211: Accuracy of decimal string to/from "binary" (non-decimal) floating-point conversions

Authors: NCITS J11, Fred Tydeman (US)
Date: 1999-10-20
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_211.htm

Summary

What is the accuracy of decimal string to/from "binary" (non-decimal) floating-point conversions?

What is the accuracy of hexadecimal string to/from "decimal" (non-power-of-2) floating-point conversions?

In the following, the phrase "decimal to binary" shall cover any pair of bases that are not both a power of the same number. It also shall cover both the string to internal floating-point and internal floating-point to string conversions.

There are two basic cases to consider at run-time:

For each of those basic cases, there are two generic sub-cases: base 10 to base 2 and base 2 to base 10.

Background
7.19.6.1 The fprintf function:

Paragraph 8 on "f,F" and "e,E" conversion specifiers says: The value is rounded to the appropriate number of digits.

Does that mean round to nearest, round by truncating, round by add 0.5 and truncate, round as per the current rounding direction, or something else? Must the rounding used for f,F match the rounding used for e,E? Since there is no explicit allowance for multiple values (as there is in 6.4.4.2 Floating constants), must the value produced be as if the infinitely precise value were rounded (and the rounding produce an error less than or equal to 0.5 units in the last place (ulp) for nearest and less than 1.0 ulp otherwise)?

For round to nearest, IEEE-754 (IEC-60559) requires that the maximum error be 0.5 ulp for a large subset of its values and 0.97 ulp for all values. For the other roundings, the maximum error allowed by IEEE-754 is 1.47 ulp. The fourth committee draft (1999-09-30) of ISO/IEC 10967-2 (LIA-2) appears to require the maximum error be in the range 0.5 to 0.75 ulp. These bounds appear to apply to both directions of conversions.

7.19.6.2 The fscanf function:

Paragraph 10 discusses conversion. Paragraph 12 on "a,e,f,g" conversion specifiers discusses format. Neither discuss accuracy of the decimal to binary conversion, e.g., it is not specified.

What is the accuracy of floating-point string to internal representation conversions? Is it the same as translation time? Is it the same as strtod? Is it undefined behavior if the value is not exactly representable? Is it round to nearest? Is it affected by the current rounding mode, e.g., correctly rounded?

7.20.1.3 The strtod ... functions:

What is the required accuracy of strtod family functions? It appears to be either not specified or the same as 6.4.4.2. It appears to depend upon what paragraph 4 "interpreted as a floating constant according to the rules of 6.4.4.2" means.

Suggested Changes

Changes to 7.19.6.1 The fprintf function:

Add near paragraph 11 before Recommended practice:

The roundings used by %f, %F, %e, and %E shall be the same and shall have an accuracy of better than 1 ulp in round to nearest and better than 2 ulp in other roundings.

Changes to 7.19.6.2 The fscanf function:

In paragraph 12, "a,e,f,g" conversion specifier, add the sentence:

The accuracy of this conversion shall be no worse than that of strtold for the same subject.

Change 7.20.1.3 The strtod ... functions:

In paragraph 4, change "rules of 6.4.4.2" to "rules of 6.4.4.2 (including accuracy requirements)"

Add a third recommended practice paragraph:

Conversions done by strtod family functions and fscanf family functions of the same valid floating-point subject string shall produce the same value.

An alternative (not liked by this author) to all of the above is to add to 5.2.4.2.2 Characteristics of floating types <float.h> in paragraph 4 before "and": ", binary-decimal conversions(footnote),".

footnote: binary-decimal covers both string to internal representations and internal to string representations, and covers any pair of bases.


Comment from WG14 on 2001-09-18:

Committee Discussion

5.2.4.2.2 paragraph 4 (which covers the accuracy of +, -, *, /, and math library functions) does not cover decimal <--> binary conversions. Therefore, the rest of 5.2.4.2.2 covers these conversions (F.P. characteristics must meet the minimum-maximum requirements for the <float.h> parameters (even though the exact model need not be followed)). That appears to require that the actual representation be able to express >= FLT/DBL/LDBL_DIG digits precise to the last of those digits (for decimal to binary conversions) and >= DECIMAL_DIG digits (for binary to decimal conversions).

6.3.1.5 para. 1 implies that the different widths of F.P. types must have similar representations differing only in number of bits in exponent, mantissa, and padding.

In 7.19.6.1 f,F format, the value is rounded to the appropriate number of digits, which indicates that the displayed value differs from the "numerical" value only with regard to that rounding. (Of course, all the fprintf conversions of numeric values to display form are on the assumption that what is displayed is the same value as the numeric value, but in human-comprehensible form and subject to specified rounding etc.)

7.20.1.3 says that the numeric string is interpreted as a value according to the rules in 6.4.4.2 for floating constants.

Details of rounding are not specified, although certain modes are described in 5.2.4.2.2.

The latitude allowed for inexactness by the standard applies only to precision of representation and to rounding mode.


Comment from WG14 on 2001-09-18:

Technical Corrigendum

Change 5.2.4.2.2 paragraph #4 to:

The accuracy of the floating-point operations ( +, -, *, /) and of the library functions in <math.h> and <complex.h> that return floating-point results is implementation defined, as is the accuracy of the conversion between floating-point internal representations and string representations performed by the libray routine in <stdio.h>, <stdlib.h> and <wchar.h>. The implementation may state that the accuracy is unknown.



Issue 0212: Binding of multibyte conversion state objects

Authors: Clive Feather (UK)
Date: 1999-10-20
Reference document: ISO/IEC WG14 N898
Status: Closed
Converted from: summary-c99.htm, dr_212.htm

Summary

At present an mbstate_t object can only ever be used to make one conversion. This is not desirable, and changes are proposed in this area.

Discussion
Clause 7.24.6 paragraph 3 reads, in part:

If an mbstate_t object has been altered by any of the functions described in this subclause, and is then used with a different multibyte character sequence, or in the other conversion direction, or with a different LC_CTYPE category setting than on earlier function calls, the behavior is undefined.

Put another way, each mbstate_t object is initially "unbound" (if it is initialized to zero) and then becomes "bound" by any call to a function such as mbrtowc or wcrtomb. When "bound" it can only be used in the same direction with the same string as originally bound, and only when the LC_CTYPE category is that in effect when it was bound. With ordinary mbstate_t objects this is a annoyance; one implication is that a new object must be created every single time a new string is to be converted (the Standard does not provide any way to "unbind" the object). With the mbstate_t object inside a FILE structure it is even worse, because it makes it impossible to (for example) write to a file, rewind it, and then read the same file. Similarly, the internal mbstate_t objects used when the mbstate_t pointer argument is set to NULL can be used for only one string in the entire program !

Users of mbstate_t objects (including those in FILE structures) expect to be able to use them for more than a single purpose.

Proposed solution
The changes introduce the concept that an mbstate_t object is either "unbound" or "bound". When set to an all-zero value (which can be at initialization or explicitly later on) it is unbound. As soon as the object is used for a conversion it becomes bound to that string, locale, and direction. Returning to the initial state does not unbind the object (in other words, while all unbound objects are in the initial state the converse is not necessarily true).

The special cases of mbrtowc and wcrtomb are defined to always result in an unbound state. This both provides more consistent behaviour (the special case resets everything to a known state) and also allows the internal mbstate_t objects associated with these functions to be unbound.

The mbstate_t object hidden in a file is returned to the unbound state whenever end of file is reached on input, and by any call to fseek (these choices were made to correspond with the requirements of 7.19.5.3 paragraph 6 for changing I/O direction).

The internal mbstate_t objects associated with the mbrlen, mbrtowc, wcrtomb, mbsrtowcs, and wcsrtombs functions can only be used with the locale they initially bind to. Other changes deal with the first three; a previously impossible case is used for the last two to force the object to the unbound state.

Suggested Technical Corrigendum

(Changes concerning explicit mbstate_t objects.)
Change 7.24.6 paragraph 3 to:

[#3] The initial conversion state corresponds, for a conversion in either direction, to the beginning of a new multibyte character in the initial shift state. An mbstate_t object may be "unbound" or "bound". A zero-valued mbstate_t object is (at least) one way to describe an unbound object, and if an mbstate_t object is assigned such a value it it becomes unbound. All unbound mbstate_t objects are in the initial conversion state (but the converse is not necessarily true).

[#3a] An unbound object can be used to initiate conversion involving any multibyte character sequence, in any LC_CTYPE category setting, in either direction; once used for a conversion, it becomes bound to that sequence, category setting, and direction. If a bound mbstate_t object is used with a different multibyte character sequence, a different LC_CTYPE category setting, or in the other conversion direction to that it is bound to, the behavior is undefined.290)

Append to footnote 290:

Furthermore, provided that the object is unbound, and thus in the initial conversion state, it can then be used in converting a new string, a new locale, or in the other direction.

Change 7.24.6.3 paragraph 1 and 7.24.6.4 paragraph 1 from:

[...] which is initialized at program startup to the initial conversion state. [...]

to:

[...] which is initialized at program startup to the unbound state. [...]

Change 7.24.6.3.2 paragraph 2 to:

[#2] If s is a null pointer, the mbrtowc function is equivalent to the call:

mbrtowc(NULL, "", 1, ps)

except that the resulting state described is unbound even if an encoding error occurred.

In this case, the values of the parameters pwc and n are ignored.

Change 7.24.6.3.3 paragraph 2 to:

[#2] If s is a null pointer, the wcrtomb function is equivalent to the call

wcrtomb(buf, L'\0',ps)

where buf is an internal buffer except that the resulting state described is always unbound even if an encoding error occurred 291a; the value of wc is ignored.

291a) The effect is reliably to make *ps unbound.

Append to 7.24.6.4 paragraph 2:

As a special case, if src is a null pointer then the normal behaviour of the function is ignored and instead ps becomes unbound irrespective of its previous state; an unspecified value is returned.

(Changes associated with streams.)
Append to 7.19.2 paragraph 6:

If a wide character input function encounters end-of-file, or after a successful call to the fseek function, thembstate_t object associated with the stream is unbound.

Append to the last sentence of 7.19.9.2 paragraph 5:

and if the stream is wide-oriented the associated mbstate_t object shall be unbound.

In 7.24.3.1 paragraph 2, change: to:

[...] If the stream is at end-of-file, the end-of-file indicator for the stream is set, the mbstate_t object associated with the stream is unbound, and fgetwc returns WEOF. [...]


Comment from WG14 on 2001-09-18:

Committee Response

The consensus is that a programmer can put an mbstate_t object in the initial conversion state for any sequence by the assignment:

static mbstate_t init_state = {0};

...

mbstate_t mystate = init_state;

This technique is used and is believed it to be portable.

There is concern about over specifying the behavior of streams. The Committee believes that to say that the state becomes unbound at EOF, would cause problems with a read/write stream that later gets extended. The Committee could not find a valid reason to hamstring the reader just because it reached an interim EOF. Moreover, is is unlikely one can portably fsetpos() in a wide stream except to the beginning or to a point that was earlier memorized with an fgetpos(). In either case, there is an obvious state to restore. Old fashioned seek()/tell() logic just doesn't full fill the requirements for a wide stream.

The Committee believes that real implementations and real applications do in fact support streams that do not begin in the initial state, as well as streams that do not end in the initial state.

It was also pointed out that even with the suggested text that required a file to begin in the initial shift state, there was no stated requirement that fopen initialize the associated mbstate_t object to have the initial shift state (which again, would break existing implementations that support files that do not begin in the initial shift state).

There is no consensus to make this change or any change along this line.



Issue 0213: Lacuna in mbrtowc

Authors: Clive Feather
Date: 1999-10-20
Reference document: ISO/IEC WG14 N900
Status: Fixed
Fixed in: C99 TC1
Converted from: summary-c99.htm, dr_213.htm

Summary

The description of the result of mbrtowc uses the term "positive" to distinguish one case from others. Unfortunately some of the other cases are also positive, because they are negative numbers cast to the (unsigned) type size_t.

The actual return value in this case is always between 1 and the value of the parameter n (inclusive): positive if the next n or fewer bytes complete a valid multibyte character (which is the value stored); the value returned is the number of bytes that complete the multibyte character.


Comment from WG14 on 2000-11-02:

Technical Corrigendum

In 7.24.6.3.2 paragraph 4, change the label of the case "positive" to "between 1 and n inclusive".



Issue 0214: atexit function registration

Authors: Clive Feather (UK)
Date: 2000-04-04
Status: Closed
Converted from: summary-c99.htm, dr_214.htm

Summary

7.20.4.2 reads:

[#3] The implementation shall support the registration of at least 32 functions.

This does not require registration of a valid function to succeed. The implementation could fail the first 420 times atexit() is called, and then succeed 32 times. It also does not require atexit() to accept any function of the correct type; theoretically an implementation could reject (say) a function in a different translation unit.

Suggested Technical Corrigendum

Change the cited wording to:

[#3] The implementation shall not reject the registration of a valid function if less than 32 functions are already registered (multiple registrations of the same function counting multiple times).

or add the following words:

If less than this number are already registered, a call with a valid argument shall succeed.


Comment from WG14 on 2001-09-18:

Committee Response

There are many conditions under which any library function or language feature may fail or behave in an undefined manner. Some examples:

As such, it is a quality of implementation issue under what conditions any library function, including atexit(), may fail.

There is no consensus to make the suggested change or any change along this line.



Issue 0215: Equality operators

Authors: Clive Feather (UK)
Date: 2000-04-04
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_215.htm

Summary

When discussing the comparison operators, 6.5.8 says:

[#4] For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.

Given that the restrictions on the arguments for pointer comparison and pointer equality are very different, it would be advisable to repeat this wording in 6.5.9. The only wording that implies that this applies to equality operators is the bit about "analogous" in 6.5.9#3. Since other restrictions (e.g. that the pointers must be in the same array) do not apply to equality operators, it is at best ambiguous whether this text applies. Therefore for clarity it should be repeated.


Comment from WG14 on 2001-09-18:

Technical Corrigendum

Paragraph 4 from 6.5.8 should be duplicated in the Semantics section of 6.5.9.



Issue 0216: Source character encodings

Authors: Clive Feather (UK)
Date: 2000-04-04
Status: Fixed
Fixed in: C99 TC1
Converted from: summary-c99.htm, dr_216.htm

Summary

The Standard is clear that the basic source character set need not have the same encoding as the basic execution character set, and that while the latter must be all positive, there is no such requirement on the former:

6.2.5:

[#3] [...] If a member of the basic execution character set is stored in a char object, its value is guaranteed to be positive.

6.10.1:

[#3] [...] Whether the numeric value for these character constants matches the value obtained when an identical character constant occurs in an expression (other than within a #if or #elif directive) is implementation-defined.141) Also, whether a single-character character constant may have a negative value is implementation-defined.

However, there are two problems with this. Firstly, the cited wording in 6.2.5 conflicts with the definition of the basic execution character set:

5.2.1:

[#2] [...] A byte with all bits set to 0, called the null character, shall exist in the basic execution character set; it is used to terminate a character string.

in that zero is not positive. Secondly, it is not clear whether a source character constant can have the value zero; in other words, can:

  #if !'A'
    #error Character A is zero
    #endif

reach the #error directive ?

Suggested Technical Corrigendum

Change the cited wording in 6.2.5 to:

#3] [...] If a member of the basic execution character set (other than the null character) is stored in a char object, its value is guaranteed to be positive.

and the last part of the cited wording in 6.10.1 to:

[#3] [...] Also, whether a single-character character constant may have a negative value is implementation-defined (nevertheless, it may not be zero).


Comment from WG14 on 2000-11-02:

Committee Response

Regarding the #error directive, 6.10.1 paragraph 3 states:

The resulting tokens compose the controlling constant expression which is evaluated according to the rules of 6.6, except that all signed integer types and all unsigned integer types act as if they have the same representation as, respectively, the types intmax_t and uintmax_t defined in the header <stdint.h>. This includes interpreting character constants, which may involve converting escape sequences into execution character set members. Whether the numeric value for these character constants matches the value obtained when an identical character constant occurs in an expression (other than within a #if or #elif directive) is implementation-defined.

The evaluation of the controlling constant expression according to the rules of 6.6 implies that character constants are converted into an execution character set (translation phase 5) just as it also implies that preprocessor tokens representing integer constants are translated into integer constants (translation phase 7).

Thus, all character constants operated upon by #if have been translated to some execution character set. The liberty given by 6.10.1 paragraph 3 that allows the value of character constants to differ in preprocessor versus non-preprocessor expressions exists to allow cross-compilers to use a standalone "native" preprocessor that is unaware of the cross-compiled target and its execution character set.

Thus, in your example, the #error directive can never be reached on a conforming implementation.

Technical Corrigendum

Change the cited wording in 6.2.5 to:

[#3] [...] If a member of the basic execution character set is stored in a char object, its value is guaranteed to be non-negative.



Issue 0217: asctime limits

Authors: Clive Feather (UK)
Date: 2000-04-04
Status: Closed
Cross-references: 0326
Converted from: summary-c99.htm, dr_217.htm

Summary

The definition of the asctime function involves a sprintf call writing into a buffer of size 26. This call will have undefined behaviour if the year being represented falls outside the range [-999, 9999]. Since applications may have relied on the size of 26, this should not be corrected by allowing the implementation to generate a longer string. This is a defect because the specification is not self-consistent and does not restrict the domain of the argument.

Suggested Technical Corrigendum

Append to 7.23.3.1[#2]:

except that if the value of timeptr->tm_year is outside the range [-2899, 8099] (and thus the represented year will not fit into four characters) it is replaced by up to 4 implementation-defined characters.


Comment from WG14 on 2001-09-18:

Committee Response

From 7.1.4 paragraph 1:

If an argument to a function has an invalid value (such as a value outside the domain of the function, or a pointer outside the address space of the program, or a null pointer, or a pointer to non-modifiable storage when the corresponding parameter is not const-qualified) or a type (after promotion) not expected by a function with variable number of arguments, the behavior is undefined.

Thus, asctime() may exhibit undefined behavior if any of the members of timeptr produce undefined behavior in the sample algorithm (for example, if the timeptr->tm_wday is outside the range 0 to 6 the function may index beyond the end of an array).

As always, the range of undefined behavior permitted includes:

There is no consensus to make the suggested change or any change along this line.



Issue 0218: Signs of non-numeric floating point values

Authors: Clive Feather (UK)
Date: 2000-04-04
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_218.htm

Summary

There is an implication at various points in the standard, notably the copysign function, that infinities and NaNs have signs. This is not the case in all implementations, and this needs to be allowed for.

Suggested Technical Corrigendum

Add a new paragraph to 5.2.4.2.2, preferably after [#3]:

[#3a] An implementation may give zero and non-numeric values (such as infinities and NaNs) a sign or may leave them unsigned. Wherever such values are unsigned, any requirement in this International Standard to retrieve the sign shall act as if the value were positive, and any requirement to set the sign shall be ignored.

or:

[...]
to retrieve the sign shall produce an unspecified sign, and any requirement to set the sign shall be ignored.


Comment from WG14 on 2001-09-18:

Committee Response

In addition to the following Technical Corrigendum, add to the Rationale section that discusses 5.2.4.2.2 of the C Standard:

The committee has been made aware of at least one implementation (VAX and Alpha in VAX mode) whose floating-point format does not support signed zeros. The hardware representation that one thinks would represent -0.0 is in fact treated as a non-numeric value similar to a NaN. Therefore, copysign(+0.0,-1.0) returns +0.0, not the expected -0.0, on this implementation. Some places that mention (or might have) signed zero results and the sign might be different than you expect:

The complex functions, in particular with branch cuts;

ceil()
conj()
copysign()
fmod()
modf()
fprintf() (Footnote 233 is OK)fwprintf() (Footnote 273 is OK)nearbyint()
nextafter()
nexttoward()
remainder() (Footnote 201 does not need to be changed)remquo()
rint()
round()
signbit()
strtod() (Footnote 249 is OK)trunc()
wcstod() (Footnote 285 is OK)

Underflow: In particular: ldexp(), scalbn(), scalbln().

Technical Corrigendum

Add a new paragraph to 5.2.4.2.2, after [#3]:

[#3a] An implementation may give zero and non-numeric values (such as infinities and NaNs) a sign or may leave them unsigned. Wherever such values are unsigned, any requirement in this International Standard to retrieve the sign shall produce an unspecified sign, and any requirement to set the sign shall be ignored.



Issue 0219: Effective types

Authors: Clive Feather (UK)
Date: 2000-04-04
Status: Closed
Converted from: summary-c99.htm, dr_219.htm

Summary

6.5 reads:

[#6] [...] If a value is copied into an object having no declared type using memcpy or memmove, or is copied as an array of character type, then the effective type of the modified object for that access and for subsequent accesses that do not modify the value is the effective type of the object from which the value is copied, if it has one. For all other accesses to an object having no declared type, the effective type of the object is simply the type of the lvalue used for the access.

Now consider the code extract:

 struct s { char c; int i; long l; double d; } s = { 1, 2, 3, 4 };
     size_t len1 = sizeof (int);
     size_t len2 = offsetof (s, d) - offsetof (s, i));
     void *p1 = malloc (len1); assert (p1);
     void *p2 = malloc (len2); assert (p2);
     memcpy (p1, (char *)&s + offsetof (s, i), len1);
     memcpy (p2, (char *)&s + offsetof (s, i), len2);

What are the effective types of p1 and p2 ? The cited text would imply that they are both struct s, even though this is patently nonsense.


Comment from WG14 on 2006-04-04:

Committee Discussion

Consider:

1. struct s { char c; int i; long l; double d; } s = { 1, 2, 3, 4 };
2. size_t len1 = sizeof (int);
3. size_t len2 = offsetof (s, d) - offsetof (s, i));
4. void *p1 = malloc (len1); assert (p1);
5. void *p2 = malloc (len2); assert (p2);
6. memcpy (p1, (char *)&s + offsetof (s, i), len1);
7. memcpy (p2, (char *)&s + offsetof (s, i), len2);

In lines 6 and 7, the type of the source object in the memcpy is an array of char because the dereference of (char *)&s + ... is a char. This is inferred by:

- "(some_type*)x" has the type "pointer to some_type"
- the dereference of "pointer to some_type" has the type "some_type"

In other words, "(char *)&s + offsetof (s,i)" has type "pointer to char" and its dereference has type "char", i.e., the type of the source object. In the following examples:

8. memcpy (p1, &s.i, len1);
9. memcpy (p1, (char *) &s.i, len1);
10. memcpy (p1, (float *) &s.i, len1);

the source types are, respectively, array of int, char, and float.

In lines 6 and 7, the effective type of the source arguments to memcpy is an array of char, based on the following sentence from 6.5P6:

"For all other accesses to an object having no declared type, the effective type of the object is simply the type of the lvalue used for the access."

Based on the following sentence again from 6.5P6:

"If a value is copied into an object having no declared type using memcpy or memmove, or is copied as an array of character type, then the effective type of the modified object for that access and for subsequent accesses that do not modify the value is the effective type of the object from which the value is copied, if it has one."

The object being copied into has no declared type (because it was an allocated object), thus "the effective type of the modified object for that access ... is the effective type of the object from which the value is copied ...". The object from which it was copied is array of char. The effective type for p1 and p2 in lines 6 and 7 is: array of char.

Committee Response

The effective types of *p1 and *p2 are not struct S because not all of the bytes of struct S are copied.

However, the memcpy calls do copy pieces of s. Those pieces contain objects with declared types.

memcpy (p1, (char *)&s + offsetof (s, i), len1); copies all of the bytes of s.i to an alignment suitable for an object of type int. The effective type of the resulting copy can be treated as having effective type int.

memcpy (p2, (char *)&s + offsetof (s, i), len2); copies all of the bytes of s.i and s.l. The memcpy also might copy bytes corresponding to padding before and after s.l.

The int object from s.i is copied to an alignment suitable for an object of type int. The object starting at *p2 extending for sizeof (int) bytes can be treated as having effective type int.

Because of alignment requirements and padding rules that vary from implementation to implementation, the long object from s.l might or might not be copied to an alignment suitable for an object of type long. If it is aligned properly, the object starting at *((char *) p2 + (offsetof (s, l) - offsetof (s, i))) extending for sizeof (long) bytes can be treated as having effective type long.

The objects resulting from the calls to memcpy may also be accessed by other types (primarily given by Subclause 6.5 paragraph 7).



Issue 0220: Definition of "decimal integer"

Authors: Clive Feather (UK)
Date: 2000-04-04
Status: Fixed
Fixed in: C99 TC1
Converted from: summary-c99.htm, dr_220.htm

Summary

7.19.6.1[#4] reads in part:

7.19.6.2 #3 reads in part:

7.24.2.1 and 7.24.2.2 have essentially the same wording.

The term "decimal integer" is defined neither in the Standard nor in ISO 2382-1. Therefore it is not possible to tell whether, in each case:

Suggested Technical Corrigendum

Add a new paragraph to 7.1.1:

[#x] A decimal integer is a sequence of digits which may begin with one or more zeros, but is nonetheless interpreted as decimal, not octal.

Append to the first cited text in 7.19.6.1:

(A leading zero will be interpreted as a flag, not as part of the width).


Comment from WG14 on 2000-11-02:

Technical Corrigendum

In 7.19.6.1P4, which reads in part:

An optional minimum field width. [...] The field width takes the form of an asterisk * (described later) or a decimal integer.[232] An optional precision [...] The precision takes the form of a period . followed either by an asterisk * (described later) or by an optional decimal integer; [...]

change "decimal integer" to "non-negative decimal integer".

In 7.19.6.2P3, which reads in part:

An optional nonzero decimal integer that specifies the maximum field width (in characters).

change "non-zero decimal integer" to "decimal integer greater than zero".

In 7.24.2.1P4, make similar changes of "decimal integer" to "non-negative decimal integer".

In 7.24.2.2P3, make similar changes of "non-zero decimal integer" to "decimal integer greater than zero".



Issue 0221: Lacuna in pointer arithmetic

Authors: Clive Feather (UK)
Date: 2000-04-04
Status: Closed
Converted from: summary-c99.htm, dr_221.htm

Summary

Consider the code extract:

int v [10]; int *p = (v + 9) + 1; int *q = v + 10;

The relevant part of 6.5.6 paragraph 8 reads:

If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression. In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i+n-th and i-n-th elements of the array object, provided they exist. Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

There is a problem with this wording in that it defines arithmetic of pointers within the array object properly, but it only defines arithmetic to "one past the end" when the pointer was previously to the last object. In other words, the initialization of p is correct because (v + 9) points to the last element of an array, but the initialization of q is not because the "i+n-th" element does not exist.

This problem also makes common idioms like:

for (p = v; p < v + 10; p++)

undefined.

It is clear that these constructs are supposed to work, and that the relevant wording just needs to be adjusted.

Suggested Technical Corrigendum

Change the cited text to:

If the pointer operand points to an element of an array object or to one past the last element of the array object, and if the array is large enough, the result points to an element, or to the location one past the last element, offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression. In other words, if the expression P points to the i-th element of an array object with k elements, or to one past the last element (in which case i equals k), then the expressions (P)+N and N+(P), (where N has the value n which may be positive, zero, or negative) both point to the i+n-th elements of the array object, provided it exists, or if i+n equals k, to one past the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object (that is, both i and i+n lie between 0 and k inclusive), the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

Similarly, change the following text in paragraph 9:

In other words, if the expressions P and Q point to, respectively, the i-th and j- th elements of an array object, the expression (P)-(Q) has the value i-j provided the value fits in an object of type ptrdiff_t. Moreover, if the expression P points either to an element of an array object or one past the last element of an array object, and the expression Q points to the last element of the same array object, the expression ((Q)+1)-(P) has the same value as ((Q)-(P))+1 and as -((P)-((Q)+1)), and has the value zero if the expression P points one past the last element of the array object, even though the expression (Q)+1 does not point to an element of the array object.88)

to:

In other words, if the expressions P and Q point to, respectively, the i-th and j-th elements of an array object with k elements, or to one past the last element (in which case i or j, or both, equals k), the expression (P)-(Q) has the value i-j provided the value fits in an object of type ptrdiff_t.88)


Comment from WG14 on 2001-09-18:

Committee Response

1. int v[10];
2. int *p = (v + 9) + 1;
3. int *q = v + 10;

Simply put, 10 == 9+1. Based on the "as-if" rule, there is no semantic distinction among any of the following:

v+9+1
(v+9)+1
v+(9+1)
v+10

and that v+x is equivalent to (v+x-1)+1 and (v+x+1)-1, assuming that x>=1 and x<=9.

Furthermore, the following wording from 6.5.6P8 confirms this equivalence:

"Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object."

The first part of the sentence states that (v+9)+1 "points to one past the last element of the array object".

The second part of the sentence states that v+10 "points to one past the last element of the array object", which equates it to (v+9)+1 because it also "points to one past the last element of the array object".

The third part of the sentence states that v+10-1 "points to the last element of the array object" which is v+9.

Additionally, the expression (v+11)-2 need not be valid because constants might not be folded and the expression (v+11) is invalid.

There are no surprising results in any of the above conclusions, even if the above constants are replaced with variables. The committee believes the current specification is clear and is unlikely to be misinterpreted.

There is no consensus to make the requested changes or any changes along these lines.



Issue 0222: Partially initialized structures

Authors: Clive Feather (UK)
Date: 2000-04-04
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_222.htm

Summary

Consider the code extract:

   struct listheader
     {
         struct item *head;
         struct item *tail;
     };
     // The following is at block scope    struct listheader h1;
     h1.head = NULL;
     struct listheader h2;
     h2 = h1;

The value of h1.tail is indeterminate throughout, but provided that the code never accesses it this is not a problem. However, if it holds a trap representation, the assignment to h2 involves assigning a trap representation, which is undefined behaviour.

There are two possible resolutions I can think of:

  1. Say that the code is defined. Any implementation that uses memberwise copying of structures now has to explicitly disable detection of trap values.
  2. Say that the code is undefined. This is going to surprise a number of people. In particular, it becomes impossible to assign any structure where the complete list of fields is unknown (e.g. any structure defined in a Standard header).

Comment from WG14 on 2001-09-18:

Committee Discussion (for history only)

A TC should remove the notion of objects of struct or union type having a trap representation. Changes need to be made to 6.2.6.1 paragraphs 6 and 7, and footnote 42. It was observed that the point of the original footnote was primarily to illustrate one reason why padding bits might not be copied: because member-by-member assignment might be performed. But member-by-member assignment would imply that struct assignment could produce undefined behavior if a member of the struct had a value that was a trap representation. Instead of adding further text explaining that member values that were trap representations were not permitted to render assignment of a containing struct or union object undefined (e.g. if member-by-member copying were used), it was decided that the footnote should simply clarify the issue of padding bits directly.


Comment from WG14 on 2001-09-18:

Technical Corrigendum

Change 6.2.6.1 paragraph #6 to:

When a value is stored in an object of structure or union type, including in a member object, the bytes of the object representation that correspond to any padding bytes take unspecified value.42) The value of a struct or union object is never a trap representation, even though the value of a member of a struct or union object may be a trap representation.

Change footnote 42 to:

42) Thus, for example, structure assignment need not copy any padding bits.

Change 6.2.6.1 paragraph #7 to:

When a value is stored in a member of an object of union type, the bytes of the object representation that do not correspond to that member but do correspond to other members take unspecified values.



Issue 0223: FP_FAST_FMAF and FP_FAST_FMAL should be integer constant

Authors: Bill Plauger (US)
Date: 2000-04-10
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_223.htm

Summary

In the standard header <math.h>, FP_FAST_FMAF and FP_FAST_FMAL should be required to be integer constant expressions.


Comment from WG14 on 2000-04-18:

Technical Corrigendum

FP_FAST_FMAF and FP_FAST_FMAL should be defined as integer constant 1.



Issue 0224: fpclassify return is not defined

Authors: Bill Plauger (US)
Date: 2000-04-10
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_224.htm

Summary

The standard header <math.h> does not define a use for FP_INFINITE and does not define what the function fpclassify returns.


Comment from WG14 on 2002-03-06:

Committee Discussion

This seems clear from a combination of 7.12.3.1 paragraph 2 and 7.12 paragraph 6.

Don't see what Plauger's comments in regard to FP_INFINITE is, and didn't consider that there is any problem.

Technical Corrigendum

In 7.12 paragraph #6 a new term "number classification macro" should be introduced, and the reword the first sentence to:

The number classification macros are:

FP_INFINITE
FP_NAN
FP_NORMAL
FP_SUBNORMAL
FP_ZERO


Issue 0225: strtod, strtof and strtold expected form of the subject sequence

Authors: Bill Plauger (US)
Date: 2000-04-10
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_225.htm

Summary

In <stdlib.h>, functions strtod, strtof, and strtold should permit an implementation to recognize either inf or infinity, and either nan or nan(n-char-sequenceopt ), not just one of each.

Suggested Technical Corrigendum

In 7.20.1.3 replace:

with:


Comment from WG14 on 2001-09-18:

Committee Discussion (for history only)

For the functions strtod, strtof and strtold, should the implementation allow INFI to work as INF and leave the pointer at the next I, or should it reject a sequence such as INFINF as an invalid sequence, that failed at the second F.

The issue concerns what degree of pushback is necessary. But these are string functions, not input functions, so they do not need push back. Furthermore, 7.19.6.2¶9 and the associated footnote, clearly indicates that there is no requirement for the strto* functions to retain symmetric functionality with fscanf, indeed that is noted as being explicitly different.

It was noted that while symmetry with scanf may have some attractiveness, that the strto* functions cannot report that the input string did not match (no error mechanism exists) and that it would just return ZERO. With scanf the error is reported.

However, the issue in the DR really reduces to the use of the term one of on the bullets in 7.20.1.3¶3. The discussion indicated we were in agreement with Clive Feather's comments on this DR.

It was also observed that these changes also apply to the wcsto* functions in 7.24.4.1


Comment from WG14 on 2001-09-18:

Technical Corrigendum

Remove the words 'one of' from the third and fourth bullets of 7.20.1.3¶3.

Remove the words 'one of' from the third and fourth bullets of 7.24.4.1¶3.



Issue 0226: strftime references

Authors: Bill Plauger (US)
Date: 2000-04-10
Status: Closed
Converted from: summary-c99.htm, dr_226.htm

Summary

In <time.h>, strftime references 7.23.1, but the reference should be 7.23.3.1.


Comment from WG14 on 2001-09-18:

Committee Response

The Standard is correct, the reference should be 7.23.1.



Issue 0227: strftime %U, %V, and %W conversion specifiers

Authors: Bill Plauger (US)
Date: 2000-04-10
Status: Closed
Converted from: summary-c99.htm, dr_227.htm

Summary

In <time.h>, strftime conversion specifiers %U, %W, and %V do not need tm_year.


Comment from WG14 on 2001-09-18:

Committee Response

The Standard is correct. tm_year is provided in the case %U and %W, to give freedom to choose the implementation (the output can be determinded using either tm_year or tm_wday, along with tm_yday). For %V it is definitely required as the computation cannot be made without tm_year.



Issue 0228: wmemcmp declaration in Annex B

Authors: Bill Plauger (US)
Date: 2000-04-10
Status: Fixed
Fixed in: C99 TC1
Converted from: summary-c99.htm, dr_228.htm

Summary

The wmemcmp declaration in Annex B should not have restrict for the arguments, and the first argument should be a const.


Comment from WG14 on 2000-11-02:

Technical Corrigendum

In Annex B, change:

int wmemcmp(wchar_t * restrict s1, const wchar_t * restrict s2, size_t n);

to:

int wmemcmp(const wchar_t *s1, const wchar_t *s2, size_t n);

Also, wmemcmp should follow wcsncpy, wmemcpy and wmemmove should follow wcsxfrm, and wcslen should follow wmemchr.



Issue 0229: localeconv() *_sep_by_space table entries issues

Authors: Project Editor (Larry Jones)
Date: 2000-04-10
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_229.htm

Summary

The int_n_sep_by_space and int_p_sep_by_space table entries in 7.11.1.1#10 are incorrect.

The n_sep_by_space entry for the Netherlands should be a 2.


Comment from WG14 on 2001-09-18:

Technical Corrigendum

In 7.11.2.1 paragraph 9:

In 7.11.2.1 paragraph 10:



Issue 0230: Enumerated type rank

Authors: Derek Jones (UK)
Date: 2000-04-11
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_230.htm

Summary

Clause 6.3.1.1p2:

An enumerated type may have a rank equal to that of int, or even greater than int.

The wording in this paragraph does not allow an object having an enumerated type equal to that of int to appear wherever an object of type int or unsigned int may appear.

Suggested Technical Corrigendum

Changing the existing wording to:

An object or expression with an integer type whose integer conversion rank is less than or equal to the rank of int and unsigned int.

solves the issue, for enumerators, at this point.

A more general solution for enumerations is to add the wording:

An enumerated type with integer conversion rank not less than the rank of int and unsigned int may be used in an expression wherever the compatible signed or unsigned integer may be; the enumerated type is converted to the compatible type. These conversions are also called integer promotions.


Comment from WG14 on 2001-01-29:

Committee Discussion

Integer conversion rank does not address enums that rank equal to int.

The words "or equal to" should be added, but there is another issue regarding enum and whether or not it can ever be greater in rank than int (or unsigned int) since the constant-expressions for the initializers are constrained to the range of values that may be expressed by an int. The words of the simple proposed change are good. The more general proposal doesn't seem to fix anything else.

Technical Corrigendum

In 6.3.1.1 paragraph 2, change the first bullet to:

An object or expression with an integer type whose integer conversion rank is less than or equal to the rank of int and unsigned int.



Issue 0231: Semantics of text-line and non-directive

Authors: Makoto Noda (Japan)
Date: 2000-04-14
Status: Closed
Cross-references: 0448
Converted from: summary-c99.htm, dr_231.htm

Summary

The semantics of text-line and non-directive are not specified in the C99 Standard.

Question
Are text-line and non-directive implementation-defined ?


Comment from WG14 on 2001-09-18:

Committee Response

The standard is correct, but provide the following words with the response, and include them in the Rationale document:

Neither text-line nor non-directive is implementation defined. They are strictly defined as sequences of pp-tokens followed by new-line. Each of these rules represents a placeholder for an intermediate state in the phases of translation, and is expressed as a non-terminal since it has no associated semantics at this phase.

However, these sequences of pp-tokens are still subject to normal processing in the subsequent phases of translation.



Issue 0232: Typo in Annex I

Authors: Makoto Noda (Japan)
Date: 2000-04-14
Status: Fixed
Fixed in: C99 TC1
Converted from: summary-c99.htm, dr_232.htm

Summary

In Annex I Common warnings the text:

the "enumeration type" should be "enumerated type".


Comment from WG14 on 2000-11-02:

Technical Corrigendum

Change "enumeration type" to "enumerated type".



Issue 0233: %g, %G precision specification

Authors: Chris Torek, Project Editor (Larry Jones)
Date: 2000-04-24
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_233.htm

Summary

7.19.6.1 (and similarly in 7.24.2.1):

g,G

A double argument representing a floating-point number is converted in style f or e (or in style F or E in the case of a G conversion specifier), with the precision specifying the number of significant digits. If the precision is zero, it is taken as 1. The style used depends on the value converted; style e (or E) is used only if the exponent resulting from such a conversion is less than -4 or greater than or equal to the precision. Trailing zeros are removed from the fractional portion of the result unless the # flag is specified; a decimal-point character appears only if it is followed by a digit.

A double argument representing an infinity or NaN is converted in the style of an f or F conversion specifier.

Assuming "significant digits" is being used in the scientific-notation sense. This means that, for instance, the number "12.34" has four significant digits. So does "0.1234", and so does "0.001234". A value like "1.200" also has four significant digits, counting trailing zeros, but not leading zeros.

Now, %g normally suppresses trailing zeros (as described above), so applying %.4g to the value 1.2 produces not "1.200" but rather just "1.2". The # modifier, however, stops the trailing-zero suppression, and:

printf("%#.4g\n", 1.2);

must produce "1.200", four significant digits.

The problem occurs when we go to print the value 0.0. No matter how many digits we tack on the end, we still have no significant digits. So what should:

printf("%#.4g\n", 0.0);

print? "0.0000" has no significant digits. "0.0" has no significant digits. "0.000000000000000000000000000000000000000" still has no significant digits. Which of these, if any, is correct output? Which of these is desirable output?

The only way this wording makes any sense is if "significant digits" means something else entirely, but then what does it mean?


Comment from WG14 on 2007-09-07:

Committee Discussion (for history only)

There seemed to be some uncertainty about whether (for the %.4g example) the exponent would be 0 or 1. This could yield different results.

Some Committee members wondered whether the exponent would be 1 or 0 for ZERO. The bullet describing e, E is clear on this though "If the value is zero, the exponent is zero".

If there is no implementation representation of ZERO, but rather a very small number. In this case, we generally thought that this was a user problem, that they could not rely on a true ZERO having a representation, in which case, they would need to place their own checks for what approximations were acceptable as ZERO and print a literal instead.

Some pathological cases were checked, and appeared to work correctly.

NOTE: In discussion, the original bullets were:

But these were changed to:

During discussion, as it was considered to be the more pure form.


Comment from WG14 on 2007-09-07:

Technical Corrigendum

Change 7.19.6.1 paragraph 8 and 7.24.2.1 paragraph 8 to:

g,G

A double argument representing a floating-point number is converted in style f or e (or in style F or E in the case of a G conversion specifier), depending on the value converted and the precision. Let P equal the precision if non-zero, 6 if the precision is omitted, or 1 if the precision is zero. Then, if a conversion with style E would have an exponent of X:

  • if P > X >= -4, the conversion is with style f (or F) and precision P - (X + 1).
  • otherwise the conversion is with style e (or E) and precision P - 1.

Finally, unless the # flag is used, any trailing zeroes are removed from the fractional portion of the result and the decimal-point character is removed if there is no fractional portion remaining.



Issue 0234: Miscellaneous Typos

Authors: WG14 Convener (John Benito)
Date: 2000-09-26
Status: Fixed
Fixed in: C99 TC1
Converted from: summary-c99.htm, dr_234.htm

Summary #1

In 6.10.3 Macro Replacement the text:

[#5] The identifier __VA_ARGS__ shall occur only in the replacement-list of a function-like macro that uses the ellipsis notation in the arguments.

The word "arguments" should be "parameters".

Summary #2
In the Foreword under major changes, VA_COPY should be va_copy .

Summary #3
In 7.11.2.1, in the description of the lconv members int_p_cs_precedes, int_n_cs_precedes, int_p_sep_by_space, and int_n_sep_by_space, the reference to int_currency_symbol should be int_curr_symbol.

Summary #4
In 7.19.6.14 The vsscanf function:

The vsscanf function returns the value of the macro EOF if an input failure occurs before any conversion. Otherwise, the vscanf function ...

The reference to vscanf should be vsscanf.

Summary #5
In 7.19.6.12 The vsnprintf function is misspelled in the synopsis.

Summary #6
In 7.4.1.12, paragraph #2, "as defined in 6.4.4.2" should be "as defined in 6.4.4.1".


Comment from WG14 on 2001-01-22:

Technical Corrigendum

In the cited text in 6.10.3, change "arguments" to "parameters"

In the Foreword, change VA_COPY to va_copy.

In 7.11.2.1, change all occurrences of int_currency_symbol to int_curr_symbol. Also, append to paragraph 5:

For int_p_sep_by_space and int_n_sep_by_space, the fourth character of int_curr_symbol is used instead of a space.

In 7.19.6.14, change the reference from vscanf to vsscanf.

In 7.19.6.12, change vsprintf to vsnprintf in the synopsis.

In 7.4.1.12, change "(as defined in 6.4.4.2)" to "(as defined in 6.4.4.1)".



Issue 0235: "C" locale collating behaviour not defined

Authors: AFNOR (Antoine Leca)
Date: 2000-10-18
Status: Closed
Converted from: summary-c99.htm, dr_235.htm

Summary

Usually, the locale-specific behaviour for the library functions is specified when it comes to the "C" locale. A noteworthy and well-known exception to that the set of printing characters is not restricted. However, other points that may be seen as overviews. In 7.21.4.3 (strcoll), 7.24.4.4.2 (wcscoll), 7.21.4.5 (strxfrm) and 7.24.4.4.4 (wcsxfrm), no behaviour is specified in the case of the "C" locale.

It is customary to default to respectively strcmp for strcoll, wcscmp for wcscoll, and the identity function for the latter two, but this is not presently required.

Suggested responses

There are basically two choices:

Suggested Technical Corrigendum

In 7.21.4.3, add a new sentence (or a new paragraph) under Description which says:

In the "C" locale, this function operates in the same way as strcmp does.

In 7.24.4.4.2, add a new sentence in paragraph 2 (or a new paragraph) which says:

In the "C" locale, this function operates in the same way as wcscmp does.

In 7.21.4.5, add a new sentence in paragraph 2 (or a new paragraph) which says:

In the "C" locale, this function copies at most n characters from the string pointed by s2 to s1.

In 7.24.4.4.4, add a new sentence in paragraph 2 (or a new paragraph) which says:

In the "C" locale, this function copies at most n wide characters from the string pointed by s2 to s1.


Comment from WG14 on 2002-03-03:

Committee Response

The committee decided to make no change. The standard does not require that strcoll() and strcmp() perform the same in the C locale.



Issue 0236: The interpretation of type based aliasing rule when applied to union objects or allocated objects

Authors: NCITS J11, Raymond Mak
Date: 2000-10-18
Status: Closed
Cross-references: 0257
Converted from: summary-c99.htm, dr_236.htm

Question

This concerns 6.5 paragraph 6 and 7. Consider the following two pieces of code :

Example 1
#define N ? // optimization opportunities if "qi" does not alias "qd"
   void f(int *qi, double *qd) {
        int i = *qi + 2;
        *qd = 3.1;       // hoist this assignment to top of function???
     *qd *= i;
     return;
   }
   main() {
      void *vp;
      int *pi;
      double *pd;
      vp = malloc(N);
      pi = vp;
      *pi = 7;    // assignment to allocated space thru "p"
      pd = vp;    // "pi" and "pd" are aliases
      f(pi, pd);
      free(vp);
    }
Example 2
// optimization opportunities if "qi" does not alias "qd"
    void f(int *qi, double *qd) {
      int i = *qi + 2;
      *qd = 3.1;       // hoist this assignment to top of function???
      *qd *= i;
      return;
   }
   main() {
     union tag {
       int mi;
       double md;
     } u;
     u.mi = 7;
     f(&u.mi, &u.md);
   }

The two pieces of code are basically the same except that one uses an union object and the other an allocated object. The question is whether these are conforming programs.

At issue here is the pointers within the function f. (This function can be in translation unit of its own and have no knowledge about the union or the allocated object.)

The spirit of the type-based aliasing rule is to help the optimizer to compute aliasing relationship without knowledge about the rest of the program. In this particular case, the type-based aliasing rule is meant to allow the optimizer to hoist the assignment *qd = 3.1 to the top of the function. But this transformation changes the computation.

6.5 paragraph 6 allows example 1. It is not clear if 6.5 paragraph 7 allows example 2. The spirit of type-based aliasing rule is violated.

Discussion:

In the second code example above.

Note that 6.5 paragraph 7 states:

"an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union)."

Arguably this can be read such that the access through u.mi in the above causes u.md to become undefined. If it were the case that u.mi was the active union member then the assignment:

*qd = 3.1;

is an error since the the store is done using an lvalue of type double and the active member has type int. However, an expression such as:

u.md = 3.14;

is legitimate because the union object is used to modify one of it's members and (in this case) changes the active member.

Similarly:

pu->md = 1.1;

changes the active member.

Turning to the first code example above.

Here again the active effective type of the allocated space starts out as type int and the desired semantics are that the assignment:

*qd = 3.1;

is an error because the expression *qd has type double.

The char type should have special privileges. Programs should be able to erase the active effective type via:

memset(vp, 0, sizeof(int));
memset(&u, 0, sizeof(union tag));

or possible change the active effective type via:

memcpy(&u, &u2, sizeof(union tag)};

or even:

char *p1 = (char *) &u;
char *p2 = (char *) &u2;
for (int i = 0; i < sizeof(union tag); i++) {
   p1[i] = p2[i];
}

That is, the char types have special alias privileges that let them scribble on an object that already has an effective type.

Suggested change:

(We offer the following as a starting point for further discussion.)

To tackle the first code example, change 6.5 paragraph 6, second sentence,

From:

If a value is stored into an object having no declared type through an lvalue having a type that is not a character type, then the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses that do not modify the stored value.

to:

If a value is stored into an object having no declared type through an lvalue having a type that is not a character type, then the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses.

That is, the last phrase "that do not modify the stored value" is removed.

To tackle the second code example, use the concept of the effective type of an union object (i.e. use it to track the active member). Either describe it in the rationale, or formally introduce it in the standard.

Effective type of an union object.

The type of the last member accessed within an union object is the effective type of the union object. For members with types not compatible with the effective type of the union object, the lvalue used for the store shall be the result of member selection from the union.

Note that this forces the union declaration to be visible in the translation unit.

If we add this to the standard, add it immediately before 6.5p7.


Comment from WG14 on 2006-05-08:

Committee Discussion

Committee believes that Example 2 violates the aliasing rules in 6.5 paragraph 7:

"an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union)."

In order to not violate the rules, function f in example should be written as:

   union tag {
                int mi;
                double md;
        } u;
        void f(int *qi, double *qd) {
                int i = *qi + 2;
                u.md = 3.1;   // union type must be used when changing effective type
                *qd *= i;
        return;
        }

Example 1 is still open. The committee does not think that the suggested wording is acceptable.

More discussion is found in reflector message #9337, and in the Curacao meeting minutes N973 and in the Santa Cruz meeting minutes N987.
The current situation requires more consideration, but general consensus seems to be;

Committee Response

Both programs invoke undefined behavior, by calling function f with pointers qi and qd that have different types but designate the same region of storage. The translator has every right to rearrange accesses to *qi and *qd by the usual aliasing rules.



Issue 0237: Declarations using [static]

Authors: WG14 Convener (J. Benito)
Date: 2001-04-25
Status: Closed
Converted from: summary-c99.htm, dr_237.htm

Summary Given the following declarations:

  void f(int n, int x[static n]);
   void f(int n, int x[n]) {}

An example at the end of 6.7.5.3 (p21) indicates that these declarations are compatible, but it seems like there should also be something about this in composite types.

  1. If some declarations include "static" and some don't, what is the effect?
  2. Does static only count if it is on the definition?
  3. Does it count if it is on the declaration visible for a given call?

Comment from WG14 on 2003-10-23:

Committee Discussion

The Committee discussed adding a footnote to 6.7.5.3 paragraph 7 along the lines of item 1.

Committee Response

The Committee believe the specification about composite types is clear enough; the composite type will be based on "qualified pointer to type", and the static keyword (and any size values) are not used.

  1. The effect is as if all of the declarations had used static and the largest size value used by any of them. Each declaration imposes requirements on all calls to the function in the program; the only way to meet all of these requirements is to always provide pointers to as many objects as the largest such value requires.
  2. No.
  3. Yes. Visibility is not relevant.


Issue 0238: Decriptions of fma() overflow and underflow errors are missing

Authors: Fred Tydeman (US)
Date: 2001-02-25
Reference document: ISO/IEC WG14 N943
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_238.htm

Summary

The description section for fma() needs to mention possible overflow and underflow errors.

Details

All, but one, of the math functions that can overflow have as part of their description, a phrase about range error. The one function that is missing it is fma().

All, but one, of the math functions that can underflow have as part of their description, a phrase about range error. The one function that is missing it is fma().

Suggested Technical Corrigendum

In 7.12.13.1 fma add to description:

A range error may occur.


Comment from WG14 on 2003-10-23:

Technical Corrigendum

In 7.12.13.1 fma add to description:

A range error may occur.



Issue 0239: Annex F nexttoward description is inconsistent with 7.12.11.4. and F.9.8.3

Authors: Fred Tydeman (US)
Date: 2001-02-25
Reference document: ISO/IEC WG14 N943
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_239.htm

Summary

The description for nexttoward() in Annex F should be changed to reference nextafter to be consistent with 7.12.11.4. and F.9.8.3.

Details

Currently, F.9.8.4 has: No additional requirements. From that, one could conclude that there is no required underflow or overflow for nexttoward by annex F. But, F.9.8.3 has two explicit error conditions on nextafter and 7.12.11.4 says nexttoward is similar to nextafter. We need to make it clear that nextafter and nexttoward have the same requirements with respect to range errors in annex F.

Suggested Technical Corrigendum

In F.9.8.4 nexttoward change:

No additional requirements.

to

No additional requirements beyond nextafter.


Comment from WG14 on 2001-10-16:

Technical Corrigendum

In F.9.8.4 nexttoward change:

No additional requirements.

to

No additional requirements beyond those on nextafter.



Issue 0240: lrint, llrint, lround, llround, and ilogb descriptions are not consistent for unrepresentable results

Authors: Fred Tydeman (US)
Date: 2001-02-25
Reference document: ISO/IEC WG14 N943
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_240.htm

Summary

lrint, llrint, lround, llround, and ilogb need to have consistent and explicit descriptions when results are too big to represent in an integer type. Also, that case should be treated as a domain error.

Details

IEC 60559 requires that when a large floating-point value, an infinity, or a NaN is converted to an integer, and the result cannot be represented as an integer in the result's format, an invalid operation has occurred. This is currently mostly reflected in C99's Annex F. This condition corresponds to C's domain error.

ilogb does not discuss (in either 7.12.6.5 or annex F) what should happen if the expected result cannot be represented as an int. It should be treated as a domain error (because it is an invalid operation to IEC 60559). The "correct" result of ilogb(0) is -infinity (which cannot be represented as an int, so should be treated as a domain error). ilogb(NaN) does not follow the normal convention of NaN in implies NaN out, so this unusual case needs to be discussed.

lrint and llrint are inconsistent on how large arguments are treated between 7.12.9.5 (range error) and Annex F (domain error).

lround and llround are inconsistent on how large arguments are treated between 7.12.9.7 (range error) and Annex F (domain error).

Suggested Technical Corrigendum

In 7.12.6.5 ilogb:

Change:

A range error may occur if x is 0.

to

A domain error occurs if x is 0, infinite, or NaN.

Add:

If the correct value is outside the range of the return type, the numeric result is unspecified, and a domain error occurs.

In 7.12.9.5 lrint llrint:

Change:

If the rounded value is outside the range of the return type, the numeric result is unspecified. A range error may occur if the magnitude of x is too large.

to

If the rounded value is outside the range of the return type, the numeric result is unspecified, and a domain error occurs.

In 7.12.9.7 lround llround:

Change:

If the rounded value is outside the range of the return type, the numeric result is unspecified. A range error may occur if the magnitude of x is too large.

to

If the rounded value is outside the range of the return type, the numeric result is unspecified, and a domain error occurs.


Comment from WG14 on 2004-03-16:

Technical Corrigendum

In 7.12.6.5 ilogb:

Change:

A range error may occur if x is 0.

to

A domain error or range error may occur if x is 0, infinite, or NaN.

Add:

If the correct value is outside the range of the return type, the numeric result is unspecified.

In F.9.3.5 ilogb:

Change:

No additional requirements.

to

If the correct result is outside the range of the return type, the numeric result is unspecified and the "invalid" floating-point exception is raised.

In 7.12.9.5 lrint and llrint:

Change:

If the rounded value is outside the range of the return type, the numeric result is unspecified. A range error may occur if the magnitude of x is too large.

to

If the rounded value is outside the range of the return type, the numeric result is unspecified, and a domain error or range error may occur.

In 7.12.9.7 lround and llround:

Change:

If the rounded value is outside the range of the return type, the numeric result is unspecified. A range error may occur if the magnitude of x is too large.

to

If the rounded value is outside the range of the return type, the numeric result is unspecified, and a domain error or range error may occur.



Issue 0241: Make the base standard and Annex F consistent for pow(0, <0)

Authors: Fred Tydeman (US)
Date: 2001-02-25
Reference document: ISO/IEC WG14 N943
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_241.htm

Summary

pow(0, <0) should be considered a pole error (result is an exact infinity) in the base standard (it already is in Annex F).

Details

pow(0, <0) is inconsistent between 7.12.7.4 (domain error) and Annex F (range error via divide-by-zero).

pow(0, <0) is effectively 1/0, which is a pole or singularity error, which is a divide-by-zero exception to Annex F and a range error to 7.12.

Counter-argument: The domain error for this case is a may, not a shall. In addition, 7.12.7.4 has

A range error may occur

without any qualifications. So, an implementation is allowed to treat this case as a range error.

Suggested Technical Corrigendum

In 7.12.7.4 pow:

Split:

A domain error may occur if x is zero and y is less than or equal to zero.

into

A domain error may occur if x is zero and y is zero.

and

A range error may occur if x is zero and y is less than zero.


Comment from WG14 on 2001-10-16:

Technical Corrigendum

In 7.12.7.4 pow:

Split:

A domain error may occur if x is zero and y is less than or equal to zero.

into:

A domain error may occur if x is zero and y is zero.

and

A domain error or range error may occur if x is zero and y is less than zero.



Issue 0242: Make the base standard and Annex F consistent for logb(0)

Authors: Fred Tydeman (US)
Date: 2001-02-25
Reference document: ISO/IEC WG14 N943
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_242.htm

Summary

logb(0) should be considered a pole error in the base standard (it already is in Annex F).

Details

logb(0) is inconsistent between 7.12.6.11 (domain error) and Annex F (range error via divide-by-zero).

logb(0) is effectively the same as log(0), log2(0), or log10(0), all of which are a pole or singularity error, which is a divide-by-zero exception to Annex F and a range error to 7.12. But, logb treats it as a domain error in 7.12.6.11.

Suggested Technical Corrigendum

In 7.12.6.11 logb:

Change:

A domain error may occur if the argument is zero.

to

A range error may occur if the argument is zero.


Comment from WG14 on 2001-10-16:

Technical Corrigendum

In 7.12.6.11 logb:

Change:

A domain error may occur if the argument is zero.

to

A domain error or range error may occur if the argument is zero.



Issue 0243: Make the base standard and Annex F consistent for fmod(), remainder(), and remquo() for a zero divisor

Authors: Fred Tydeman (US)
Date: 2001-02-25
Reference document: ISO/IEC WG14 N943
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_243.htm

Summary

fmod(), remainder(), and remquo() should be made consistent with each other when the divisor is zero. There are two "correct" behaviours when the divisor is zero: Treat it as a domain error (cannot divide by zero), or, based upon limits, compute a zero remainder. This series of changes may also require that IEEE-754 be changed (to allow a zero result in addition to the currently required invalid operation). Assuming that fmod(), remainder(), and remquo() should be consistent with each other, the following needs to be done.

An alternative is to do some of these changes, or changes along these lines.

It is assumed that requiring just the return of zero behaviour is too drastic as there are many millions of chips already doing the invalid operation behaviour.

Details

For a fixed x, as one takes the limit as y approaches zero, the remainder of x/y approaches zero (0 <= |result| < |y|) and the quotient is unspecified.

IEC 60559 requires that x REM y, when y is zero, be an invalid operation, e.g., a domain error.

fmod(x,0) is currently allowed to be either 0 or a domain error by 7.12.10.1, while Annex F requires it to be an invalid exception, e.g., domain error.

remainder(x,0) is currently unspecified by 7.12.10.2, while Annex F requires it to be an invalid exception, e.g., domain error.

remquo(x,0) is currently unspecified by 7.12.10.3, while Annex F requires it to be an invalid exception, e.g., domain error. In addition, nothing is said about the quotient that is stored for this case.

Counter-argument: These functions are discontinuous along the lines y = mx or y = (m+1/2)x for integers m. We see no reason to "take the limit as y approaches zero".

Allowing two different behaviours for these functions for the same arguments, will cause applications to be more complicated, with no real added benefit.

Counter-counter-argument: By discontinuous, I assume you mean that they are like saw-tooth shaped functions, e.g., a linear rise and a vertical fall. I agree with that, but, as one approaches the line y=0, the height of the teeth gets smaller and smaller.

Suggested Technical Corrigendum

In 7.12.10.1 fmod:

No change needed.

In 7.12.10.2 remainder:

Add to Returns:

If y is zero, whether a domain error occurs or the remainder functions return zero is implementation defined.

In 7.12.10.3 remquo:

Add to Returns:

If y is zero, whether a domain error occurs or the remquo functions return zero is implementation defined.

If y is zero, the quotient stored is unspecified.

In F.9.7.1 fmod:

Change

fmod(x,y) returns a NaN and raises the "invalid" floating-point exception for x infinite or y zero.

to two items:

fmod(x,y) returns a NaN and raises the "invalid" floating-point exception for x infinite.

and

For y zero, fmod(x,y) either returns a zero (with sign of x), or returns a NaN and raises the "invalid" floating-point exception.

In F.9.7.2 remainder:

Add:

For y zero, remainder(x,y) either returns a zero (with sign of x), or returns a NaN and raises the "invalid" floating-point exception.

In F.9.7.3 remquo:

Add:

For y zero, remquo(x,y) either returns a zero (with sign of x), or returns a NaN and raises the "invalid" floating-point exception; and, in both cases, has an unspecified quotient stored.

Also add,

When remquo returns a NaN, the quotient stored is unspecified.


Comment from WG14 on 2001-10-16:

Technical Corrigendum

In 7.12.10.2 remainder:

Add to Returns:

If y is zero, whether a domain error occurs or the remainder functions return zero is implementation defined.

In 7.12.10.3 remquo:

Add to Returns:

If y is zero, whether a domain error occurs or the remquo functions return zero is implementation defined.

If y is zero, the quotient stored is unspecified.

In J.3.12 Library functions:

Add (after fmod):

Whether a domain error occurs or zero is returned when an remainder function has a second argument of zero (7.12.10.2).

Whether a domain error occurs or zero is returned when an remquo function has a second argument of zero (7.12.10.3).



Issue 0244: tgamma(zero or negative integer) should be considered a pole error

Authors: Fred Tydeman (US)
Date: 2001-02-25
Reference document: ISO/IEC WG14 N943
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_244.htm

Summary

tgamma(zero or negative integer)should be considered a pole error since the correct mathematical result is an exact infinity (whose sign depends upon the side that the limit is taken from). Annex F already does this for the zero argument case.

Details

When the correct mathematical result is an exact infinity (from finite arguments), it is considered a pole or singularity error. This is true if the result's sign is independent of the direction of the limit. It is believed to be true that it still is a pole error if the sign of the infinite result depends upon the direction of the limit.

Some symbolic math packages support the concept of +/-infinity in addition to +infinity and -infinity, and in those, tgamma(zero or negative integer) is +/-infinity.

Since +/-infinity cannot be represented in most (all?) floating-point formats, return +infinity for that value.

LIA-2 treats similar cases (math function with exact non-zero integer argument and a result of +/-infinity, such as tan(90 degrees)) as a pole error with the result of signed infinity.

Counter-argument: For 0.0 we have the luxury of +0.0 and -0.0. Non-zero integers don't have "sides". There is no concept of +/-infinity in IEC 60559 (nor any other hardware floating-point representation), just +infinity and -infinity. If there is no one correct result for a given argument, then that case must be considered an invalid operation or a domain error. tgamma(negative integer) has two results (+infinity or -infinity), so must be considered invalid. tgamma(x), as x approaches -infinity, has no unique limit, so must also be considered invalid.

Suggested Technical Corrigendum

In 7.12.8.4 tgamma:

Change:

A domain error occurs if x is a negative integer or if the result cannot be represented when x is zero.

to

A range error may occur if x is a negative integer or zero.

In F.9.5.4 tgamma:

Change:

tgamma(x) returns a NaN and raises the "invalid" floating-point exception for x a negative integer.

to

tgamma(x) returns +INF and raises the "divide-by-zero" floating-point exception for x a negative integer.

Change:

tgamma(-INF) returns a NaN and raises the "invalid" floating-point exception.

to

tgamma(-INF) returns +INF and raises the "divide-by-zero" floating-point exception.


Comment from WG14 on 2001-10-16:

Technical Corrigendum

In 7.12.8.4 tgamma:

Change:

A domain error occurs if x is a negative integer or if the result cannot be represented when x is zero.

to

A domain error or range error may occur if x is a negative integer or zero.



Issue 0245: Missing paragraph numbers

Authors: WG14
Date: 2001-09-21
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_245.htm

Summary

  1. In F.9.8.4, the second paragraph is missing a paragraph number.
  2. In 7.20.7.2, the first paragraph of the Returns section is missing a paragraph number.
  3. In 7.18.2.1, the first paragraph is missing a paragraph number.
  4. In 7.18.2.2, the first paragraph is missing a paragraph number.
  5. In 7.18.2.3, the first paragraph is missing a paragraph number.
  6. In 7.18.2.4, the first paragraph is missing a paragraph number.
  7. In 7.18.2.5, the first paragraph is missing a paragraph number.
  8. In 7.19.4.3 Recommended Practice, the first paragraph is missing a paragraph number.
  9. In 7.21.4.3 Description, the first paragraph is missing a paragraph number.
  10. In G.3, the first paragraph is missing a paragraph number.
  11. In G.6.2.2, the first paragraph is missing a paragraph number.

Suggested Technical Corrigendum

Add the missing paragraph number in F.9.8.4, 7.20.7.2, 7.18.2.1, 7.18.2.2, 7.18.2.3, 7.18.2.4, 7.18.2.5, 7.19.4.3, 7.21.4.3, G.3 and G.6.2.2


Comment from WG14 on 2003-03-06:

Technical Corrigendum

Add the missing paragraph number in F.9.8.4, 7.20.7.2, 7.18.2.1, 7.18.2.2, 7.18.2.3, 7.18.2.4, 7.18.2.5, 7.19.4.3, 7.21.4.3, G.3 and G.6.2.2



Issue 0246: completion of declarators

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Closed
Converted from: summary-c99.htm, dr_246.htm

Problem

6.2.1#7 reads in part:

Any other identifier has scope that begins just after the completion of its declarator.

However, nothing says when a declarator is completed. While it seems obvious to experienced people that this means the syntactic end of the declarator, the term "complete" has other meanings when discussing declarations and objects, and therefore it's a bad term to use.

Suggested Technical Corrigendum

Change the quoted text to:

Any other identifier has scope that begins just after the end of the full declarator it appears in.


Comment from WG14 on 2002-03-06:

Committee Response

The suggested words don't appear to be an improvement; the current phrasing is clear enough.



Issue 0247: are values a form of behaviour ?

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_247.htm

Problem

I can see nothing that says or implies that production of an unspecified value is a form of unspecified behaviour, and similarly for implementation-defined values. It is therefore arguable that a program is strictly-conforming even if its output depends on an unspecified value.

Suggested Technical Corrigendum

Add a new paragraph 4#2a after 4#2:

[#2a] An evaluation that makes use of an unspecified or implementation-defined value is a form of unspecified or implementation-defined behaviour respectively.


Comment from WG14 on 2002-03-06:

Technical Corrigendum

In section 3.4.4, prepend

"Use of an unspecified value, or other ..." before "behavior where".



Issue 0248: limits are required for optional types

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_248.htm

Problem

The types sig_atomic_t and wchar_t are optional on freestanding implementations, since they don't have to provide the relevant headers. But the limits SIG_ATOMIC_MIN, SIG_ATOMIC_MAX, WINT_MIN, and WINT_MAX are in <stdint.h>, which all implementations must provide. So a freestanding implementation must provide limits for types which it doesn't implement.

Suggested Technical Corrigendum

Append to 7.18.3#2:

A freestanding implementation shall only define the symbols corresponding to those typedef names it actually provides.


Comment from WG14 on 2002-03-06:

Technical Corrigendum

Append to 7.18.3#2:

An implementation shall define only the macros corresponding to those typedef names it actually provides.

Add a footnote to the last sentence of 7.18.3#2 to read:

A freestanding implementation need not provide all of these types.



Issue 0249: Lacuna applying C89:TC1 to C99

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_249.htm

Problem

Defect Report 009 made a change to the text concerning function declarators. This text seems not have made it into C99, even though the issue remains valid. The change should be reinstated.

Suggested Technical Corrigendum

Change 6.7.5.3#11 to:

[#11] If, in a parameter declaration, an identifier can be treated as a typedef name or as a parameter name, it shall be taken as a typedef name.


Comment from WG14 on 2002-03-06:

Technical Corrigendum

Change 6.7.5.3#11 to:

If, in a parameter declaration, an identifier can be treated as a typedef name or as a parameter name, it shall be taken as a typedef name.



Issue 0250: non-directives within macro arguments

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Fixed
Fixed in: C99 TC2
Cross-references: 0303, 0448
Converted from: summary-c99.htm, dr_250.htm

Problem

Consider the code:

  #define nothing(x) // Nothing    /* Case 1 */
    nothing (
    #include <stdio.h>
    )
    /* Case 2 */
    nothing (
    #nonstandard
    )

6.10.3#11 reads in part:

If there are sequences of preprocessing tokens within the list of arguments that would otherwise act as preprocessing directives, the behavior is undefined.

This clearly covers case 1. However, it is not clear whether or not case 2 is a preprocessing directive. It is a "non-directive", but is that also a directive ? If case 2 is a directive, it is undefined behaviour. If it is not, then case 2 is strictly-conforming and macro-expands to nothing.

Since non-directives are only valid as extensions, it might be more sensible for them to behave as directives do and make the behaviour undefined in this case.

Suggested Technical Corrigendum

In 6.10.3#11, change the last sentence to:

If there are sequences of preprocessing tokens within the list of arguments that would otherwise act as preprocessing directives or as non-directives (that is, the first pre-processing token on a line is a #), the behavior is undefined.


Comment from WG14 on 2002-03-06:

Committee Response

The Committee believes the Standard is correct (preprocessing directive includes non-directive), therefore, the anwser to the question on this is yes.

Technical Corrigendum

In 6.10 #2, italicize the term "preprocessing directive".

In 6.10.3 paragraph 11, last sentence. After "preprocessing directives", add the following footnote.

Despite the name, a non-directive is a preprocessing directive.



Issue 0251: are struct fred and union fred the same type ?

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_251.htm

Problem

Consider the code:

 union fred { int a; }
    int main (void)
    {
        struct fred *ptr;  /* Line X */
        // ...

I can see nothing that forbids this code. In particular, 6.7.2.3#8 reads:

[#8] If a type specifier of the form

        struct-or-union identifier

or

        enum identifier

occurs other than as part of one of the above forms, and a declaration of the identifier as a tag is visible, then it specifies the same type as that other declaration, and does not redeclare the tag.

At line X a declaration of fred as a tag is visible, so this line specifies the same type as that other declaration, even though this uses struct and that uses union !

It has been further pointed out to me that nothing in the Standard actually says that union x is a union type as opposed to a structure type, and vice versa.

Suggested Technical Corrigendum

Append to 6.7.2.1#6:

The keywords struct and union indicate that the type being specified is, respectively, a structure type or a union type.

Add a new paragraph following 6.7.2.3#1:

[#1a] Where two declarations that use the same tag declare the same type, they shall both use the same choice of struct, union, or enum.


Comment from WG14 on 2006-03-29:

Committee Discussion

The Committee is inclined to accept the suggested TC, but the issue is still being debated.

Technical Corrigendum

Append to 6.7.2.1#6:

The keywords struct and union indicate that the type being specified is, respectively, a structure type or a union type.

Add a new paragraph following 6.7.2.3#1:

[#1a] Where two declarations that use the same tag declare the same type, they shall both use the same choice of struct, union, or enum.



Issue 0252: incomplete argument types when calling non-prototyped functions

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_252.htm

Problem

Consider the code:

   void jim ();
    void sheila (void);
    // ...   sheila (jim ());   /* Line A */
    jim (sheila ());   /* Line B */

Line A violates the constraint of 6.5.2.2#2, that requires the argument to have a type that can be assigned to the parameter type. But line B doesn't because that constraint only applies to prototyped functions. 6.5.2.2#4 reads in part:

[#4] An argument may be an expression of any object type.

but this is not a constraint. Should it not be ? After all, the compiler has to know the type of the argument in order to compile the function call, so it can check at that point that the argument has a complete object type.

Suggested Technical Corrigendum

Add a new paragraph #1a following 6.5.2.2#1:

[#1a] Each argument shall have a type which is a completed object type.


Comment from WG14 on 2002-03-06:

Committee Response

This should not be a constraint.



Issue 0253: "overriding" in designated initializers

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Closed
Cross-references: 0413
Converted from: summary-c99.htm, dr_253.htm

Problem

Consider the code:

   struct fred
    {
        char s [6];
        int n;
    };
    struct fred x [] = { { { "abc" }, 1 }, [0].s[0] = 'q'        };
    struct fred y [] = { { { "abc" }, 1 }, [0] = { .s[0] = 'q' } };

Both x and y will contain one element of type struct fred, which will be initialized by the initializer { { "abc" }, 1 } and then modified in some way. The question is exactly how it is modified.

6.7.8#19 reads:

[#19] The initialization shall occur in initializer list order, each initializer provided for a particular subobject overriding any previously listed initializer for the same subobject; all subobjects that are not initialized explicitly shall be initialized implicitly the same as objects that have static storage duration.

In the case of x, it is fairly clear that the first initializer sets:

   x [0].s [0] = 'a'
    x [0].s [1] = 'b'
    x [0].s [2] = 'c'
    x [0].s [3] = '\0'
    x [0].n     = 1

and the second one sets:

   x [0].s [0] = 'q'

Finally, the remaining subobjects are initialized implicitly:

   x [0].s [4] = 0
    x [0].s [5] = 0

Now consider the second initializer for y. One point of view says that this behaves the same as for x: it specifies a value for y [0].s [0], after which the two remaining elements of y [0].s are still uninitialized and so are set to zero. The other point of view says that this sets:

   y [0] = (struct fred) { .s[0] = 'q' }

and that the rule concerning "all subobjects that are not initialized explicitly" applies recursively. If so, the effect is to set:

   x [0].s [0] = 'q'
    x [0].s [1] = 0
    x [0].s [2] = 0
    x [0].s [3] = 0
    x [0].s [4] = 0
    x [0].s [5] = 0
    x [0].n     = 0

Which of these is correct ?

Suggested Technical Corrigendum 1

If x and y are supposed to have the same effect, change 6.7.8#19 to:

[#19] The initialization shall occur in initializer list order, each initializer provided for a particular subobject overriding any previously listed initializer for the same subobject. When all initializers have been applied, any subobjects of the overall object being initialized that have not been initialized explicitly shall be initialized implicitly the same as objects that have static storage duration.

and add a new paragraph at the end:

[#39] To illustrate the rules for implicit initialization, in:

       struct fred
        {
            char s [6];
            int n;
        };
        struct fred x [] = { { { "abc" }, 1 }, [0].s[0] = 'q'        };
        struct fred y [] = { { { "abc" }, 1 }, [0] = { .s[0] = 'q' } };

the definitions of x and y result in identical objects. Each will be an array with one element; within that element, the members s[4] and s[5] are implicitly initialized to zero.

Suggested Technical Corrigendum 2

If x and y are supposed to be different, change 6.7.8#19 to:

[#19] The initialization shall occur in initializer list order, each initializer provided for a particular subobject overriding any previously listed initializer for the same subobject; for each brace-enclosed list, all subobjects within the object that that list initializes that are not initialized explicitly shall be initialized implicitly the same as objects that have static storage duration.

and add a new paragraph at the end:

[#39] To illustrate the rules for implicit initialization, in:

       struct fred
        {
            char s [6];
            int n;
        };
        struct fred x [] = { { { "abc" }, 1 }, [0] = { .s[0] = 'q' } };
        struct fred y [] = { { .s[0] = 'q' } };

the definitions of x and y result in identical objects. Each will be an array with one element; within that element, all the members are implicitly initialized to zero except for s[0]. In the definition of x the first initializer has no effect, since the second one initializes the same subobject (x[0]).


Comment from WG14 on 2002-05-15:

Committee Response

Given the example

   struct fred
    {
        char s [6];
        int n;
    };
    struct fred y [] = { { { "abc" }, 1 }, [0] = { .s[0] = 'q' } };

6.7.8#21 makes it clear already that { .s[0] = 'q' } initializes a whole object of type "struct fred" whose members (other than s[0]) are initialized as though they were static storage, so this initialization of y[0] overrides the previous one. Thus, all subobjects of y[0] other than s[0] are zeroed. Paragraph #21 of 6.7.8 also makes it clear that the initializations for x and y are different.

Committee Discussion

The tem "designated initializer" is never mentioned in the Standard though it appears in the index and new features section (the Standard uses the term "designation initializer" in the text).



Issue 0254: mbtowc and partial characters

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Closed
Converted from: summary-c99.htm, dr_254.htm

Problem

If mbtowc() is given a partial character (or an escape sequence that isn't a complete character), it returns -1. However, is it supposed to remember the relevant state information or should it ignore it ?

Consider an implementation where the character '\xE' starts an alternate shift state and '\xF' returns to the initial shift state. The wide character encodings are:

initial shift state: 'x' maps to ASCII codes
alternate shift state: 'x' maps to ASCII codes + 0x100

Starting in the initial shift state,

   mbtowc (&wc, "\xEZ", 2);

should return 2 and set wc to 0x15A. However, starting in the initial shift state, consider:

   mbtowc (&wc1, "\xE", 1);
    mbtowc (&wc2, "Z",   1);

I would expect that the first call returns -1, leaving wc1 unaltered, while the second returns 1 and sets wc2 to 0x5A. However, is it permitted for the second to set wc2 to 0x15A ? If so, how is an application meant to use mbtowc ?

[The newer function mbrtowc does not have this problem.]

Suggested Technical Corrigendum

The UK C Panel prefers to add a new return value for this case. To do so, change the main part (see the previous DR) of 7.20.7.2#3 to read:

If s is a null pointer, the mbtowc function returns a nonzero or zero value, if multibyte character encodings, respectively, do or do not have state-dependent encodings. If s is not a null pointer, the mbtowc function returns the first of the following that applies (given the current conversion state):

0 if s points to the null character
between 1 and n inclusive if the next n or fewer bytes complete a valid multibyte character (which is the value stored); the value returned is the number of bytes that complete the multibyte character. The value returned will not be greater than that of the MB_CUR_MAX macro.
(size_t)(-2) if the next n bytes contribute to an incomplete (but potentially valid) multibyte character, and all n bytes have been processed (no value is stored).
(size_t)(-1) if an encoding error occurs, in which case the next n or fewer bytes do not contribute to a complete and valid multibyte character (no value is stored); the value of the macro EILSEQ is stored in errno, and the conversion state is unspecified.

(note that most of this wording comes from mbrtowc) and delete #4.

If this option is unacceptable, then append to 7.20.7.2#2:

If the next multibyte character is incomplete or invalid, the shift state is unaffected and nothing is stored.


Comment from WG14 on 2002-03-06:

Committee Response

The Committee believe the behavior of this example is unspecified. The mbrtowc() function provides a superior migration path, so we are leaving this alone.



Issue 0255: non-prototyped function calls and argument mismatches

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Closed
Cross-references: 0316
Converted from: summary-c99.htm, dr_255.htm

Problem

Consider the code:

   #include <stdio.h>
    int f ();
    int main (void)
    {
        return f (0);
    }
    #ifdef PROTO
    int f (unsigned int x)
    #else
    int f (x) unsigned int x;
    #endif
    {
        return printf ("%u\n", x);
    }

Now, 6.5.2.2#6 reads:

[#6] If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions.
[...]
If the function is defined with a type that includes a prototype, and either the prototype ends with an ellipsis (, ...) or the types of the arguments after promotion are not compatible with the types of the parameters, the behavior is undefined. If the function is defined with a type that does not include a prototype, and the types of the arguments after promotion are not compatible with those of the parameters after promotion, the behavior is undefined, except for the following cases:

So the above code is undefined if PROTO is defined, but is legitimate if it is not. This seems inconsistent.

Traditionally, when a function is called and no prototype is in scope, the implementation applies the default argument promotions to the argument value and then assumes that is the parameter type. If it isn't, this can cause all kinds of problems, which is why the undefined behaviour. However, if it is known that the argument value will be correctly handled by the parameter type, there is no problem; this is the rationale behind the exceptions.

The exceptions should apply to both cases, no matter how the function is eventually defined.

Suggested Technical Corrigendum

Change the part of 6.5.2.2#6 after the omission to:

If the types of the arguments after promotion are not compatible with those of the parameters after promotion 78A), the behavior is undefined, except for the following cases:

If the function is defined with a type that includes a prototype, and either any parameter has a type which is altered by the default argument promotions or the prototype ends with an ellipsis (, ...), the behavior is undefined.

78A) Because of the rule later in this paragraph, it is only necessary to check whether the parameter type undergoes promotion when the function is not defined using a prototype.


Comment from WG14 on 2002-05-15:

Committee Response

The Committee does not wish to further refine the behavior of calls not in the scope of prototypes. In practice, this will not be a problem, and the Committee does not wish to define the behavior.



Issue 0256: multiple inclusion of headers

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Closed
Converted from: summary-c99.htm, dr_256.htm

Problem

Consider the code:

   #include <stdio.h>     // Line 1
    #undef FOPEN_MAX       // Line 2, permitted by 7.1.3#3    #include <stdio.h>     // Line 3    #ifdef FOPEN_MAX       // Line 4

7.1.2 says:

[#4] Standard headers may be included in any order; each may be included more than once in a given scope, with no effect different from being included only once, except that the effect of including <assert.h> depends on the definition of NDEBUG (see 7.2).

Does "with no effect different" mean:

  1. the includes on lines 1 and 3 have the same effect, so at line 4 the macro FOPEN_MAX is defined;
  2. the include on line 3 has no effect, so that at line 4 the macro FOPEN_MAX is undefined;
  3. something else ?

Most current implementations wrap the contents of headers with an "idempotent guard", such as:

   #ifndef _STDIO_H_INCLUDED_
    #define _STDIO_H_INCLUDED_
    // Real contents go here   #endif

This will provide behaviour (2), which I would suggest is the most desirable.

Furthermore, the concept of scope doesn't apply here, both because includes happen during preprocessing and because there is a requirement in the same paragraph that:

If used, a header shall be included outside of any external declaration or definition,

If the wording is being altered, this would be a good opportunity to fix this as well.

Suggested Technical Corrigendum

Change the first sentence of 7.1.2#4 to:

[#4] Standard headers may be included in any order; each may be included any number of times in a preprocessing translation unit. The second and subsequent occurrences of a given header shall be ignored, except in the case of <assert.h> (where the behaviour is defined in subclause 7.2).


Comment from WG14 on 2002-03-06:

Committee Response

The Committee believe that both answer 1 and 2 are allowed, and does not see a compelling reason to change this.



Issue 0257: common initial sequences and related issues with unions

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Closed
Cross-references: 0236, 0283
Converted from: summary-c99.htm, dr_257.htm

Problem

6.5.2.3#5 reads:

[#5] One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the complete type of the union is visible. Two structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members.

Two possible reasons have been suggested for this rule.

  1. The implementation may put padding between structure members. This rule is necessary to ensure that the common initial sequence uses the same padding in both places, so that the corresponding members occupy the same location.

  2. If we consider part of the second example in 6.5.2.3#8:

       struct t1 { int m; };
        struct t2 { int m; };
        int f(struct t1 * p1, struct t2 * p2)
        {
            if (p1->m < 0)
                p2->m = -p2->m;
            return p1->m;
        }
    

    the rule is necessary for an implementation to realize that p1 and p2 might refer the same location.

If (1) is the reason, then the example is a bad one because the two members are both at the start of their respective structures, and therefore are required to be at an offset of 0 from the start of the structure (and therefore of the union). It should be changed to use a member further along a common initial sequence.

On the other hand, the requirement is not actually very suitable. Consider the code:

   struct t1 { int x; double y; char z; } s1;
    struct t2 { int i; double q; unsigned long u; } s2;
    void f1 (struct t1 *p) { p->y = sqrt ((double) p->x); }
    void f2 (struct t2 *p) { p->q = sqrt ((double) p->i); }

    union { struct t1 t1; struct t2 t2; } u;
    // Followed by code using the common initial sequence property

The implementation might wish to use different padding in structures t1 and t2. It is prevented from doing so by the existence of the union, but a one-pass compilation will not become aware of this until after compiling f1 and f2. Therefore it will have to assume, when deciding the layout of the structures, that there might be a union. Therefore the rule about a union type being visible is useless.

If, on the other hand, (2) is the reason, then the wording does not address enough cases. For example, consider a version of the example in 6.5.2.3#8 where one member is signed and the other is unsigned.

   struct t1 { signed   int m; };
    struct t2 { unsigned int m; };
    int f(struct t1 * p1, struct t2 * p2)
    {
        if (p1->m > 0)
            p2->m = p2->m * 2;
        return p1->m;
    }

There is no common initial sequence but nevertheless many of the same issues apply. On the other hand, the correct way for a function such as f to protect itself against such aliasing is not to rely on the rule in 6.5.2.3#8, but rather to use the restrict qualifier.

I would suggest, therefore, that (2) is not a valid reason for the rule. As stated above, a corollary of this discussion is that the "union type must be visible" rule is useless.

Finally, one of the changes from C90 to C99 was to remove any restriction on accessing one member of a union when the last store was to a different one. The rationale was that the behaviour would then depend on the representations of the values. Since this point is often misunderstood, it might well be worth making it clear in the Standard.

Suggested Technical Corrigendum

To address point (1), in 6.5.2.3#8, second example, change the two structures to:

           struct t1 { double d; int m; };
            struct t2 { double d; int m; };

To address the wider point about visibility, change the first part of 6.5.2.3#5 to read:

[#5] One special guarantee is made in order to simplify the use of unions: if several structure types share a common initial sequence (see below), then corresponding members are required to lie at the same offset from the start of the union. Therefore if a union contains two or more such structures, the common initial part may be inspected using any of them, no matter which one was used to store the value.

To address issues about "similar" types raised in point (2) above, change the second part of #5 to read:

Two structures share a common initial sequence if corresponding members have matching types for a sequence of one or more initial members. Two types, in turn, are matching if they are

To address the issue about "type punning", attach a new footnote 78a to the words "named member" in 6.5.2.3#3:

78a If the member used to access the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called "type punning"). This might be a trap representation.

Note: all the above changes are independent of one another, depending on the committee's view of the issues.


Comment from WG14 on 2002-10-17:

Committee Response

The current rules are the result of extensive previous deliberations. The Committee does not see a defect here.

Committee Discussion

  1. The Committee agrees, but does not believe that this is a defect in the Standard (or a substantive problem). There is some support for changing the example.
  2. This takes away the "visibility rule" and the Committee does not want to do that; this is related to DR 236.
  3. The Committee agrees, but does not believe a change is warranted at this time. This should be considered for a future revision of the Standard.
  4. The Committee believes this is a separate issue, and should be a defect report (and possibly a new footnote). The defect report generated is DR 283, also see N980.


Issue 0258: ordering of "defined" and macro replacement

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Closed
Converted from: summary-c99.htm, dr_258.htm

Problem

Consider the code:

  #define repeat(x) x && x    // Line 1   #if repeat(defined fred)    // Line 2

and the code:

  #define forget(x) 0         // Line 3   #if forget(defined fred)    // Line 4

6.10.1#3 says:

[#3] Prior to evaluation, macro invocations in the list of preprocessing tokens that will become the controlling constant expression are replaced (except for those macro names modified by the defined unary operator), just as in normal text. If the token defined is generated as a result of this replacement process or use of the defined unary operator does not match one of the two specified forms prior to macro replacement, the behavior is undefined.

Does line 2 "generate" a defined operator ? Is line 4 strictly conforming code, or does the fact that macro expansion "forgets" the defined operator cause a problem ?

The restriction was clearly intended to make code like the following undefined:

   #define jim defined
    #if jim loves sheila

I would guess that the original intention was that any defined X pair in the original source worked correctly. The proposed change would resolve this.

In addition, given the order of events, it is unsuitable to say that a defined X expression is "evaluated". Rather it should be described as a textual substitution.

Suggested Technical Corrigendum

Change 6.10.1#1 to read:

[...]

     defined identifier

or

     defined ( identifier )

which are replaced by the token 1 if the identifier is currently
[...]
subject identifier), or the token 0 if it is not.

and #3 to read:

[#3] Prior to evaluation, the list of preprocessing tokens that will become the controlling constant expression is examined. Firstly all expressions using the defined operator are replaced as described above, and then macro invocations are replaced, just as in normal text. If the token defined appears in the list after the replacement process, or the use of the defined unary operator does not match one of the two specified forms prior to macro replacement, the behavior is undefined. After all [...]


Comment from WG14 on 2002-03-06:

Committee Response

The standard does not clearly specify what happens in this case, so portable programs should not use these sorts of constructs.



Issue 0259: macro invocations with no arguments

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Closed
Converted from: summary-c99.htm, dr_259.htm

Problem

Consider the code:

   #define m0()  replacement
    #define m1(x) begin x end
    m0() m1()

The number of arguments in a macro invocation is defined by 6.10.3#11:

[#11] The sequence of preprocessing tokens bounded by the outside-most matching parentheses forms the list of arguments for the function-like macro. The individual arguments within the list are separated by comma preprocessing tokens, but comma preprocessing tokens between matching inner parentheses do not separate arguments.

while 6.10.3#4 reads:

[#4] If the identifier-list in the macro definition does not end with an ellipsis, the number of arguments (including those arguments consisting of no preprocessing tokens) in an invocation of a function-like macro shall equal the number of parameters in the macro definition. Otherwise, there shall be more arguments in the invocation than there are parameters in the macro definition (excluding the ...). There shall exist a ) preprocessing token that terminates the invocation.

Now:

EITHER: the invocation of m0 has a single argument,
OR: the invocation of m1 has no arguments,

and in either case the requirement of 6.10.3#4 is violated.

This is clearly not the intent.

Suggested Technical Corrigendum

Append to 6.10.3#4:

If the invocation has no preprocessing tokens between the parentheses, this shall count as one argument unless the macro definition has neither an identifier list nor an ellipsis, in which case it shall count as no arguments.


Comment from WG14 on 2002-03-06:

Committee Response

The standard is clear enough, and no change is needed.



Issue 0260: indeterminate values and identical representations

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Closed
Cross-references: 0451
Converted from: summary-c99.htm, dr_260.htm

Problem

This is an intermingling of something that started out as two separate questions:

  1. if an object holds an indeterminate value, can that value change other than by an explicit action of the program ?
  2. if two objects hold identical representations derived from different sources, can they be used exchangeably ?

However, after much discussion the UK C Panel decided that they were better treated together. Both involve the concept of the "provenance" of a value.

Consider the code:

 char *p;
    unsigned char cp [sizeof p];
    p = malloc (SOME_VALUE);
    // Assume the allocation succeeds
    // Other code omitted that does not alter p.  memcpy (cp, &p, sizeof p);
    (free)(p); // Point X
               // ...
               // Point Y  if (memcmp (cp, &p, sizeof p))
              // ...

After the call to free the value of p is indeterminate. Is the implementation allowed, at this point (point X), to change this indeterminate value (presumably through compiler magic) so that the memcmp function sees a difference, or must the value remain constant ? Can it make the change later, between points X and Y ?

It is suggested that this is implied by 6.2.4#2:

An object [...] retains its last-stored value throughout its lifetime.

particularly if each byte of an object is also an object.

On the other hand, such a requirement would eliminate useful optimisation and debugging opportunities. (As an example of an optimisation, if p has been loaded into a register and then modified, it need not be written back to memory; as an example of a debugging opportunity, p could be set to a null pointer or to a detectable value).

[Note that where an object contains padding, 6.2.6.1#6 and #7 allows the value of padding bits and bytes to change whenever the object changes.]

If an implementation is allowed to change the value of p, then consider the code:

 char *p, *q, *r;
    p = malloc (SOME_VALUE);
    // Assume the allocation succeeds  q = p;
    r = p + 1;
    // Other code omitted that does not alter p, q, or r  (free)(p);
    // Point Z

Can it change the value of q or r at point Z ? What about later ?

Now consider the code:

 int *p, *q;
    p = malloc (sizeof (int)); assert (p != NULL);
    (free)(p);
    q = malloc (sizeof (int)); assert (q != NULL);
    if (memcmp (&p, &q, sizeof p) == 0)
    {
        // Assume this point is reached
        *p = 42;  // Line A

Is the assignment valid (because an assignment using *q would have been, and the two variables hold identical values) ? Or is it invalid because the last-stored value of p is now indeterminate (because of the free) ?

Similarly, consider the code:

 int x, y;
    int *p, *q;
    p = &x + 1;
    q = &y;
    if (memcmp (&p, &q, sizeof p) == 0)
    {
        // Assume this point is reached     *q = 42; p [-1] = 42;   // Line B     *p = 42; q [-1] = 42;   // Line C

The assignments on line B are clearly valid, but what about those on line C ? After all, p and q are identical, even in their hidden bits. What if we then add:

     int *r;
        remote_memcpy (&r, &p, sizeof p);   // See note      *r = 42;      // Line D      r [-1] = 42;  // Line E

(The function remote_memcpy is identical to memcpy, but it is done in another translation unit so that the compiler cannot associate special semantics with it.) Which, if either, of the assignments is allowed ?

Another example is the program:

 static int *p;
    void f (int n)
    {
        int sum = 0;
        int *q = &n;
        if (memcmp (&p, &q, sizeof p) == 0)
            for (int i = 0; i < n; i++)
                sum += i, p [i] = 0;
        p = &n;
    }
    int main (void)
    {
        int x;
        p = &x;
        f (1);
        f (6);
        return 0;
    }

On the first call to f the test is false. Therefore p is set to point to n. The value of p becomes indeterminate at the end of the call, but on most implementations this will have no effect. On the second call the test is true. Therefore the first time round the loop p [0], which is n, will be set to 0 and the loop will terminate.

However, most implementations would reasonably assume that n is not changed by anything in the loop and generate code accordingly. If the behaviour were undefined for some reason, such an implementation would be conforming. But is it strictly-conforming or is it undefined ?

Finally, note that we can generate a similar situation without giving the compiler any clue in advance:

 void f (int vec [], int n)
    {
        void *vp;
        int *p;
        printf ("%p or %p", (void *) vec, (void *) &n);    // Line Q      scanf ("%p", &vp); p = vp;
        for (int i = 0; i < n; i++)
            p [i] = 0;
    }

The user could ensure that p is set to either of the values printed. If a debugger is used, it isn't even necessary to retain line Q to determine the value to enter on stdin, and therefore the compiler has no warning that the address of n is being taken.

Resolution

After much discussion, the UK C Panel came to a number of conclusions as to what it would be desirable for the Standard to mean. These can be expressed as three requirements.

  1. The implementation is entitled to take account of the provenance of a pointer value when determining what actions are and are not defined. Thus the assignments on lines A and C involve undefined behaviour. Similarly line D would be undefined and line E valid, though in practice a compiler would probably assume that p could point anywhere.
  2. Where a pointer value becomes indeterminate because the object pointed to has reached the end of its lifetime, all objects whose effective type is a pointer and that point to the same object acquire an indeterminate value. Thus p at point X, and p, q, and r at point Z, can all change their value.
  3. At any time that the compiler can determine that an object contains an indeterminate value, even if the type of the object does not have trap representations, the object may change value arbitrarily. Thus p need not have the same values at lines X and Y. As soon as the object is given an explicit value, this behaviour stops.

Suggested Technical Corrigendum

Change 3.17.2 to:

[#1] indeterminate value
a value which, at any given moment, could be either an unspecified value or a trap representation.

[#2] While an object holds an indeterminate value it is indeterminate. Successive reads from an object that is indeterminate might return different results. Storing a value in an object, other than an indeterminate value, means that the object is no longer indeterminate.

Change the last sentence of 6.2.4#2 from:

The value of a pointer becomes indeterminate when the object it points to reaches the end of its lifetime.

to:

When an object reaches the end of its lifetime, any object with an effective type that is a pointer type and that points to that object becomes indeterminate.

[Various uses of the word "indeterminate" could be tidied up, but this is the only one where the meaning needs to change.]

Add a new paragraph to 6.5.3.2:

[#5] The implementation is permitted to use the derivation of a pointer value in determining whether or not access through that pointer is undefined behaviour, even if the pointer compares equal to, or has the same representation as, a different pointer for which the access would be permitted. For example, if two objects with the same type have non-overlapping lifetimes and happened to occupy the same address, a pointer to one cannot be used to access the other.

[The * operator seems a reasonable place to put this. However, it could equally be elsewhere.]


Comment from WG14 on 2004-09-28:

Committee Discussion (for history only)

Result does not mean the same as value. This is undefined because 6.5.6#8 has a 'shall' in it. The bits have to stay the same. 6.4.2 applies.

A bit pattern + type does not imply a unique value. There can be more than one bit pattern that represents the same value. C only requires that an object with a determinate value retain that value during its lifetime unless a an explicit action (assignment, increment, decrement or through such functions as memcpy and memmove) change that value to another one or renders the value indeterminate.

An indeterminate value may be represented by any bit pattern. The C Standard lays down no requirement that two inspections of the bits representing a given value will observe the same bit-pattern only that the observed pattern on each occasion will be a valid representation of the value.

In addition the C Standard does not prohibit an implementation from tracking the provenance of the bit-pattern representing a value. An indeterminate value happening to have a bit pattern that is identical to a bit pattern representing a determinate value is not sufficient to allow access to the indeterminate value free from undefined behavior.

In reaching our response we noted that requiring immutable bit patterns for indeterminate values would reduce optimization opportunities. For example, it would require tracking of the actual bit-patterns of indeterminate values if the memory containing them were paged out. That seems an unnecessary constraint on optimizers with no compensatory benefit to programmers.

Committee Response

Question 1:

Values may have any bit-pattern that validly represents them and the implementation is free to move between alternate representations (for example, it may normalize pointers, floating-point representations etc.). In the case of an indeterminate value all bit-patterns are valid representations and the actual bit-pattern may change without direct action of the program.

Question 2:

If two objects have identical bit-pattern representations and their types are the same they may still compare as unequal (for example if one object has an indeterminate value) and if one is an indeterminate value attempting to read such an object invokes undefined behavior. Implementations are permitted to track the origins of a bit-pattern and treat those representing an indeterminate value as distinct from those representing a determined value. They may also treat pointers based on different origins as distinct even though they are bitwise identical.

Note that using assignment or bitwise copying via memcpy or memmove of a determinate value makes the destination acquire the same determinate value.



Issue 0261: constant expressions

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Closed
Converted from: summary-c99.htm, dr_261.htm

Problem

When is an expression a constant expression ?

Consider the code (at block scope):

 enum e1 { ex1 = INT_MAX + 1 };        // Line E1  enum e2 { ex2 = INT_MAX + (0, 1) };   // Line E2  char *p1 = (1 - 1);                   // Line P1  char *p2 = (42, 1 - 1);               // Line P2  short s1 = 42 + (0, 1);               // Line S1  p1 = (42, 1 - 1);                     // Line X1  s1 = (42, 69);                        // Line X2  p2 = 0;                               // Line X3  p2 = 1 - 1;                           // Line X4

On line E1 the syntax says that INT_MAX + 1 is a constant-expr. Therefore this is a constant expression, the requirements of 6.6 apply, and line E2 violates the constraint in 6.6#3.

On the remaining lines the syntax says that the code following the = sign is an assignment-expr; at no point in the parse does a constant-expr occur. So are these constant expressions ?

For line P1 to be legitimate, the expression (1 - 1) must be an integer constant expression (6.3.2.3#3). This implies that any expression comprised entirely of constants is an integer constant expression. So line P2 violates the constraint in 6.6#3 and, rather more worryingly, so does line S1.

If a generic initializer can be a constant expression, then, surely, so can any other expression. This means that lines X1 and X2 violate the constraint in 6.6#3. On the other hand, if they are not constant expressions, then the right hand sides on lines X3 and X4 do not include a null pointer constant; nor does line P1.

Consider also:

static int v = sizeof (int [(2, 2)]);

This is legitimate if, and only if, (2, 2) is a constant expression.

It would appear that the term "constant expression" actually has four subtly different meanings.

  1. An object in the syntax. Where the syntax tree contains constant-expr the resulting code must meet the constraints and semantics of 6.6. An example is 6.7.2.2, where explicit values for enumeration constants must be constant-exprs.
  2. A requirement on the program that a given construct must, in context, be a constant expression even though in other contexts the expression need not be constant. An example is 6.7.8#4: if the object has static storage duration, the initializer is subject to the constraints and semantics of 6.6, but if it has automatic storage duration there is no such requirement.
  3. A requirement on the implementation that an entity must be a constant expression. For example, this applies to macros in standard headers. The implementation is not conforming if the definition does not meet the syntax, constraints, and semantic requirements of 6.6.
  4. A test that distinguishes two cases. An example is 6.3.2.3#3, where a certain subset of integer expressions (those that are constant-exprs and have a value of 0) are also null pointer constants. It is not clear whether expressions that break the constraints or semantic requirements are erroneous or are simply not constant expressions.

The Standard needs to make clear when each of these four cases applies.

On further examination, cases (1) and (2) appear to always be obvious from the text of the Standard. Case (3) appears only to apply to macros defined in standard headers or predefined. Case (4) is harder to identify, but I believe that there are only two situations:

- null pointer constants;
- determining whether a type is variably modified.

Suggested Technical Corrigendum

Replace 6.6#2 with the following:

[#2] A constant expression is one which is evaluated during translation rather than runtime, usually because the precise value will affect the translation in some way.

[#2a] Where the implementation is required to provide a constant expression, that expression shall be one that, if included in the appropriate context, would meet the requirements of this subclause and whose evaluation would not involve undefined behaviour.

[#2b] An expression has a translation-time value if it meets the requirements of this subclause and evaluation would not involve undefined behaviour. If the expression fails to meet these requirements (for example, an integer expression includes a comma operator or a cast to a floating type), the expression does not have a translation-time value but nevertheless is not necessarily invalid.

Change 6.3.2.3#3 to begin:

[#3] An integer expression with the translation-time value 0, or such an expression cast to type void *, is called a null pointer constant.55)

Change 6.7.5.2#1 to read, in part:

[...] an integer type. If the expression has a translation-time value, it shall be greater than zero. The element type [...]

the last part of #4 to read:

If the size is an integer expression with a translation-time value and the element type has a known constant size, the array type is not a variable length array type; otherwise, the array type is a variable length array type.

#5 to begin:

[#5] If the size is an expression that does not have a translation-time value: if it occurs [...]

#6 to begin:

[#6] For two array types to be compatible, both shall have compatible element types, and if both size specifiers are present and have translation-time values, then both size specifiers shall have the same value.

and add a new example:

[#11] EXAMPLE 5: an expression that contains only constants but breaks one or more of the rules of 6.6 does not have a translation-time value. Therefore, in:

     int fla [5];       // not a VLA, "5" has a translation-time value      int vla [(0, 5)];  // VLA, 6.6 forbids comma operators

This can be used to force an array to have a constant size but still be variably modified.


Comment from WG14 on 2003-10-06:

Committee Discussion (for history only)
The semantics and grammar overlap.
The grammar says "this is an expression".
The semantics says "this is a constant expression"

Committee Response

The Committee agrees with your analysis of "constant expression" and the division into four categories.

We agree that line P1 is legitimate because "(1-1)" is a constant expression. Lines P2 and S1 do not include constant expressions because:

Line S1 is legitimate, while line P2 violates the constraints of 6.5.16.1#3 (the right hand side must either have pointer to character or pointer to void type, or must be a null pointer constant). Line X1 violates the same constraint for the same reason (this was also addressed in DR 064).

Line X2 is legitimate because there is no requirement for the right hand side to be a constant expression. Lines X3 and X4 are legitimate because the expressions are constant expressions with value 0 and therefore null pointer constants.

The Committee also agrees that:

    int fla [(0+5)];     // is a normal array, not variably modified
    int vla [(0,5)];     // is a variable length array

In general, the interpretation of an expression for constantness is context sensitive. For any expression which contains only constants:

In summary, provided the above points are taken account of, the Committee does not believe the Standard is ambiguous nor that it is necessary to modify it to make this clearer.



Issue 0262: maximum size of bit fields

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Fixed
Fixed in: C99 TC2
Cross-references: 0335
Converted from: summary-c99.htm, dr_262.htm

Problem

6.7.2.1#3 reads, in part:

[#3] The expression that specifies the width of a bit-field shall be an integer constant expression that has nonnegative value that shall not exceed the number of bits in an object of the type that is specified if the colon and expression are omitted.

Is "the number of bits of the type ..." the width or is it the number of bits in the object representation ?

Since it might not be practical to make use of padding bits in such an object, the former would be more sensible.

Suggested Technical Corrigendum

Change the cited text to read:

[#3] The expression that specifies the width of a bit-field shall be an integer constant expression that has nonnegative value that shall not exceed the width of an object of the type that is specified if the colon and expression are omitted.

(bold type shows the changed words)


Comment from WG14 on 2002-03-07:

Technical Corrigendum

Change 6.7.2.1#3 to read:

The expression that specifies the width of a bit-field shall be an integer constant expression that has nonnegative value that shall not exceed the width of an object of the type that is specified if the colon and expression are omitted.



Issue 0263: all-zero bits representations

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_263.htm

Problem

Consider the code:

   int v [10];
    memset (v, 0, sizeof v);

Most programmers would expect this code to set all the elements of v to zero. However, the code is actually undefined: it is possible for int to have a representation in which all-bits-zero is a trap representation (for example, if there is an odd-parity bit in the value).

Consider also:

   int *p;
    p = calloc (n_members, sizeof (int));

This problem applies to all integer types except for unsigned char. I believe that the idiom is well-enough known that it should be made a part of the Standard.

Suggested Technical Corrigendum

Append to 6.2.6.2#5:

For any integer type, the object representation where all the bits are zero shall be a representation of the value zero in that type.


Comment from WG14 on 2002-03-07:

Technical Corrigendum

Append to 6.2.6.2#5:

For any integer type, the object representation where all the bits are zero shall be a representation of the value zero in that type.



Issue 0264: graphic characters

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Closed
Converted from: summary-c99.htm, dr_264.htm

Problem

The Standard uses the terms "printing character", "graphic character", and "nongraphic character". The first is discussed in 5.2.2#1 and defined formally in 7.4#3:

[#3] The term printing character refers to a member of a locale-specific set of characters, each of which occupies one printing position on a display device;

A "nongraphic character" is clearly a character which is not a graphic character, but "graphic character" is nowhere defined. It is used only in 5.2.1#3, which requires "the following 29 graphic characters" to be part of the basic character sets, while "nongraphic character" is used in 5.2.2#2 and 6.4.4.4#8 when discussing the \a \b \f \n \r \t and \v escape sequences.

The key questions are:

  1. Are the 29 enumerated graphic characters required to be printing characters ?
  2. Are isalnum() and isspace() required to be false for them ?
  3. Is ispunct() required to be true for them ?

In addition, given that the seven characters corresponding to the escape sequences above are required to be control characters (see 5.2.1#3):

  1. Should "nongraphic character" be replaced by "control character" ?

I believe that the answers should be:

  1. yes
  2. yes;
  3. yes in the C locale, but not otherwise;
  4. yes.

However, it is not clear that these answers can be derived from the Standard (though if (1) and (2) are "yes", (3) must at least be "yes in the C locale").

Suggested Technical Corrigendum

To address (1): in 5.2.1#3, replace "29 graphic characters" with "29 printing characters".

To address (4): in 5.2.2#2 and 6.4.4.4#8 replace "nongraphic" with "control".

To address (2): append to 5.2.1#4:

A graphical mark character is one of the 29 other printing characters listed above.

in 7.4.1.2#2, insert between the two sentences:

The isalpha function returns false for all graphical mark characters.

and in 7.4.1.10#2, change "characters for which" to "characters which are not graphical mark characters and for which".

Given the above changes, (3) can be derived from the modified Standard.


Comment from WG14 on 2002-03-07:

Committee Response

The referenced sections in the standard only use the term "non-graphic character" in the context of backslash-escape sequences, for which the standard is clear enough, and no changes are needed.



Issue 0265: preprocessor arithmetic

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_265.htm

Problem

Assume that both compile-time and run-time arithmetic have 2's complement, no trap representations, 8/16/32/48/64 bit integer types. Consider the code:

  #if -0xFFFFFFFF < 0

Is this expression true or false ? 6.10.1#3 reads, in part:

and then each preprocessing token is converted into a token. The resulting tokens compose the controlling constant expression which is evaluated according to the rules of 6.6, except that all signed integer types and all unsigned integer types act as if they have the same representation as, respectively, the types intmax_t and uintmax_t defined in the header <stdint.h>.

Does the "except" wording apply to the conversion to a token, or only to the evaluation of the expression ? If the former, then 0xFFFFFFFF can be represented in an int (intmax_t), it has a signed type, and the expression is true. If the latter, 0xFFFFFFFF cannot be represented in an int but can be represented in an unsigned int, so it has unsigned type and the expression is false.

I believe that the former was intended, with the preprocessor only having to consider one pair of integer types.

Suggested Technical Corrigendum

Change the cited text to:

and then each preprocessing token is converted into a token. The resulting tokens compose the controlling constant expression which is evaluated according to the rules of 6.6. For the purposes of the conversion and evaluation all signed integer types and all unsigned integer types act as if they have the same representation as, respectively, the types intmax_t and uintmax_t defined in the header <stdint.h>.

(bold type shows the changed words)

Add a footnote reference to the end of this text, and add the footnote:

140a Thus on an implementation where INT_MAX is 0x7FFF and UINT_MAX is 0xFFFF, the constant 0x8000 is signed within a #if expression even though it is unsigned in translation phase 7.


Comment from WG14 on 2002-05-15:

Technical Corrigendum

Change 6.10.1#3 to read:

...

and then each preprocessing token is converted into a token. The resulting tokens compose the controlling constant expression which is evaluated according to the rules of 6.6. For the purposes of this token conversion and evaluation all signed integer types and all unsigned integer types act as if they have the same representation as, respectively, the types intmax_t and uintmax_t defined in the header <stdint.h>.

Add a footnote to the end of 6.10.1#3 to read:

Thus on an implementation where INT_MAX is 0x7FFF and UINT_MAX is 0xFFFF, the constant 0x8000 is signed and positive within a #if expression even though it is unsigned in translation phase 7.



Issue 0266: overflow of sizeof

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Closed
Converted from: summary-c99.htm, dr_266.htm

Problem

Consider the following code:

  char x [SIZE_MAX / 2][SIZE_MAX / 2];
    size_t s = sizeof x;

The size of x cannot be fitted into an object of type size_t. Assuming that SIZE_MAX is 65535, what is the value of s ? More generally, which of the following is, or should be, the case ?

  1. The value is reduced modulo (SIZE_MAX + 1).
  2. The behaviour is undefined (or perhaps implementation-defined).
  3. The program is forbidden to use sizeof with such a large argument.
  4. The implementation must ensure that no object can be larger than SIZE_MAX bytes.

6.5.3.4#2 says in part:

[#2] The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer.

Note that there is no indication that the result may be other than the correct size.

Suggested Technical Corrigendum

One of:

  1. Append to 6.5.3.4#4:

    If the size is too large to fit in an object of type size_t, it is converted to that type in the manner described in subclause 6.3.1.3.

  2. Append to 6.5.3.4#4:

    If the size is too large to fit in an object of type size_t, it is replaced by an implementation-defined value.

  3. Add a new constraint paragraph after 6.5.3.4#1:

    [#1a] The sizeof operator shall not be applied to an operand whose size, in bytes, is larger than the maximum value of the type size_t.

  4. Append to 6.5.3.4#4:

    The implementation shall ensure that the type size_t is large enough to hold the result of all uses of the sizeof operator.

[Some of these are less than wonderful, and consideration should also be given to the interaction with VLAs.]


Comment from WG14 on 2004-03-06:

Committee Discussion

The committee has deliberated and decided that more than one interpretation is reasonable. Translation limits do not apply to objects whose size is determined at runtime.

sizeof(a[SIZE_MAX/2][SIZE_MAX/2]);

The program is not strictly conforming because it exceeds an environmental limit.
If the implementation generates code, there is no requirement for a diagnostic. In the event that sizeof is called on the object, a diagnostic should be issued, but not required.
VLAs are a special case.

Committee Response

The program is not strictly conforming because it exceeds an environmental limit. If the implementation generates code, there is no requirement for a diagnostic. In the event that sizeof is called on the object, a diagnostic can be issued, but is not required.



Issue 0267: Typos in 5.1.2.3, 7.24.4.4.5, 7.24.6.1, 7.24.6.1

Authors: WG14 Convener (J. Benito)
Date: 2001-09-21
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_267.htm

Summary

  1. 5.1.2.3p12, example 4, expressions should be expression.
  2. 7.24.4.4.5p1 * s1 and * s2 should not have spaces following the *s.
  3. 7.24.6.1.1p3 "The btowc returns" should read "The btowc function returns".
  4. 7.24.6.1.2p3 "The wctob returns" should read "The wctob function returns".

Suggested Technical Corrigendum

  1. In 5.1.2.3, paragraph #12 change last line of code fragment expressions to expression.

  2. In 7.24.4.4.5, paragraph #1 remove the space following the * for s1 and s2.

  3. In 7.24.6.1.1, paragraph #3 change:

    "The btowc returns"

    to

    "The btowc function returns"

  4. In 7.24.6.1.2, paragraph #3 change:

    "The wctob returns"

    to

    The wctob function returns"


Comment from WG14 on 2003-10-06:

Technical Corrigendum

  1. In 5.1.2.3, paragraph #12 change expressions to expression in last line of code fragment.

  2. In 7.24.4.4.5, paragraph #1 remove the space following the * for s1 and s2.

  3. In 7.24.6.1.1, paragraph #3 change:

    "The btowc returns"

    to

    "The btowc function returns"

  4. In 7.24.6.1.2, paragraph #3 change:

    "The wctob returns"

    to

    The wctob function returns"



Issue 0268: jumps into iteration statements

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_268.htm

Problem

Consider the code:

int x = 0;
    goto centre;
    while (++x < 10)
    {
        // Some code centre:
        // More code }

"Everyone knows" that, when the end of the block is reached, the loop test is evaluated in the normal way. Nevertheless, I can find nothing in the Standard that says so (it is implied by the example in 6.8.6.1#3, but that is all). Note that in:

int x;
    // ... if (condition) { x = -1; goto true_case; }
    // ... if (x > 0)
      true_case:
        do_something ();
    else
        do_something_else ();

the else case is not executed after a jump to true_case, even though the condition x > 0 is false. Therefore it is not possible to argue from analogy; note also that this latter case is spelled out in the Standard. Since this technique is well-known, it ought to be well-defined.

Suggested Technical Corrigendum

Add a new paragraph after 6.8.5#4:

[#4a] If the loop body is reached by a jump from outside the iteration statement, the behavior is as if the body were entered in the normal way. That is, when the end of the body is reached the controlling expression is evaluated (and, in the case of a for statement, expr-3 is evaluated first) and the body re-executed if it is not 0. Similarly, a break or continue statement has the appropriate effect. However, the code jumped over - including the controlling expressions in the case of a while or for statement - is not evaluated when the jump happens.

Possibly also add an example either as 6.8.5#6 or 6.8.6.1#5 (with appropriate editorial changes):

[#6] EXAMPLE: A jump into a for statement does not execute clause-1 at all or expr-2 during the jump:

  int i = 5;
        if (condition) goto body;
        for (i = 0; i < 10; i++)
        {
            if (i > 2) i++;
        body:
            printf (" %d", i);
        }
        printf ("\n");

If condition is true, this prints:

  5 7 9

while if it is false it prints:

  0 1 2 4 6 8 10

Comment from WG14 on 2006-03-29:

Committee Discussion

While we agree that this may be a defect, we are not happy with the proposed words, and processing this defect is postponed pending improved wording. Specifically, "as if the body were entered in the normal way" raises a few new questions.

Technical Corrigendum

Append to 6.8.5#4:

The repetition occurs regardless of whether the loop body is entered from the iteration statement or by a jump.*

* Code jumped over is not executed. In particular, the controlling expression of a for or while statement is not evaluated before entering the loop body, nor is clause-1 of a for statement.



Issue 0269: lacunae in exact-width integer types

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_269.htm

Problem 7.18.1.1 reads:

[#1] The typedef name intN_t designates a signed integer type with width N, no padding bits, and a two's complement representation. Thus, int8_t denotes a signed integer type with a width of exactly 8 bits.

[#2] The typedef name uintN_t designates an unsigned integer type with width N. Thus, uint24_t denotes an unsigned integer type with a width of exactly 24 bits.

[#3] These types are optional. However, if an implementation provides integer types with widths of 8, 16, 32, or 64 bits, it shall define the corresponding typedef names.

The requirements for no padding bits and two's complement were added at a late stage, and the implications to the text weren't fully thought through. In particular:

Suggested Technical Corrigendum

Change this section to read:

[#1] The typedef name intN_t designates a signed integer type with width N, no padding bits, and a two's complement representation. Thus, int8_t denotes a signed integer type with a width of exactly 8 bits and those other properties.

[#2] The typedef name uintN_t designates an unsigned integer type with width N and no padding bits. Thus, uint24_t denotes an unsigned integer type with a width of exactly 24 bits and no padding bits.

[#3] These types are optional. However, if an implementation provides integer types with widths of 8, 16, 32, or 64 bits, no padding bits, and (for the signed types) that have a two's complement representation, it shall define the corresponding typedef names.

Or, alternatively:

[#3] These types are optional. However, if an implementation has a type with width 8, 16, 32, or 64 bits that meet the above requirements, it shall define the corresponding typedef names.


Comment from WG14 on 2002-05-15:

Committee Response

The first bullet point is false; while the second sentence is not a complete specification, it does not contradict the first sentence.

Technical Corrigendum

Change 7.18.1.1#3 to read:

These types are optional. However, if an implementation provides integer types with widths of 8, 16, 32, or 64 bits, no padding bits, and (for the signed types) that have a two's complement representation, it shall define the corresponding typedef names.

Committee Discussion

The Committee believes that suggestion 2 (about unsigned types) should be considered for a future revision of the Standard.



Issue 0270: wint_t is not the promoted version of wchar_t

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_270.htm

Problem

In the fprintf conversion specifier "%lc", the corresponding argument is of type wint_t, but is then treated as if it contained a wchar_t value. In 7.19.6.1#18, the last call is:

  fprintf(stdout, "|%13lc|\n", wstr[5]);

This argument has the type wchar_t.

There is no requirement in the Standard that the default argument promotions convert wchar_t to wint_t. Therefore this example exhibits undefined behaviour on some implementations. Nonetheless, the code looks like it ought to work, and WG14 should consider changing the definition of wint_t to force it.

The current definition of wint_t is in 7.24.1#2:

wint_t

which is an integer type unchanged by default argument promotions that can hold any value corresponding to members of the extended character set, as well as at least one value that does not correspond to any member of the extended character set (see WEOF below);269) and

269wchar_t and wint_t can be the same integer type.

Three possible solutions are:

  1. Fix the example.
  2. Change the definition of wint_t to be the promoted version of wchar_t.
  3. Change the definition of %lc to take promoted wchar_t rather than wint_t.

Suggested Technical Corrigendum 1

Change the quoted line of 7.19.6.1#18 to:

  fprintf(stdout, "|%13lc|\n", (wint_t) wstr[5]);

Suggested Technical Corrigendum 2

Change the cited portion of 7.24.1#2 to:

wint_t which is the integer type resulting when the default argument promotions are applied to the type wchar_t;269) and

Suggested Technical Corrigendum 3

[Italics are used to show the changed text.]

Change 7.19.6.1#7 and 7.24.2.1#7, l modifier, to:

l (ell) Specifies that a following d, i, o, u, x, or X conversion specifier applies to a long int or unsigned long int argument; that a following n conversion specifier applies to a pointer to a long int argument; that a following c conversion specifier applies to an argument whose type is that resulting when the default argument conversions are applied to the type wchar_t; that a following s conversion specifier applies to a pointer to a wchar_t argument; or has no effect on a following a, A, e, E, f, F, g, or G conversion specifier.

Change 7.19.6.1#8, c specifier, second paragraph, to:

If an l length modifier is present*, the argument - whose type is that resulting when the default argument conversions are applied to the type wchar_t* - is converted as if by an ls conversion specification with no precision and an argument that points to the initial element of a two-element array of wchar_t, the first element containing the argument to the lc conversion specification and the second a null wide character.

Change 7.24.2.1#8, c specifier, second paragraph, to:

If an l length modifier is present, the argument is converted to wchar_t and written.


Comment from WG14 on 2002-03-07:

Technical Corrigendum

Change the quoted line of 7.19.6.1#18 to:

  fprintf(stdout, "|%13lc|\n", (wint_t) wstr[5]);


Issue 0271: lacuna in iswctype and towctrans

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Closed
Converted from: summary-c99.htm, dr_271.htm

Problem

Consider the calls:

   iswctype (c, wctype (property))
    towctrans (c, wctrans (property))

where property is not valid in the current locale. The wctype and wctrans functions return zero, but the behaviour of iswctype and towctrans is not specified.

I believe it would be useful - and considered natural - for them to return 0 ("c does not have this property") and c ("c is unaffected by this mapping") respectively.

Suggested Technical Corrigendum

Append to 7.25.2.2.1#4:

If desc is zero, the iswctype function returns zero (false).

Append to 7.25.3.2.1#4:

If desc is zero, the towctrans function returns the value of wc.


Comment from WG14 on 2002-05-15:

Committee Response

Since no behavior is specified when desc is zero, for either iswctype() or towctrans(), the behavior is undefined. We do not believe it would be appropriate to add new requirements here.

Committee Discussion

The Committee believes this should be considered for a future revision of the Standard.



Issue 0272: type category

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_272.htm

Problem

The concept of "type category" is defined but is never used in a useful way; it is also used inconsistently. The term and its cognates appear in only six places:

6.2.5#24: defines the term;
6.2.5#25: qualified and unqualified versions of types belong to the same category;
6.2.5#27: example: (float *) has category "pointer";
6.2.5#28: example: (struct tag (*[5])(float)) has category "array";
footnote 93: "... removes any type qualifiers from the type category of the expression"
footnote 137: "The intent is that the type category in a function definition cannot be inherited from a typedef."

Note how the use in footnote 93 conflicts with that in #25, and that the use in footnote 137 remains less than clear.

Having an unnecessary term defined leaves the reader confused to no benefit. The term should be removed and the remaining wording changed.

Even if the other changes described here are foregone, footnote 93 is in error and should be changed.

Suggested Technical Corrigendum

Delete 6.2.5#24.

In 6.2.5#25, delete "belong to the same type category and".

In 6.2.5#27, change "Its type category is pointer" to "It is a pointer type".

In 6.2.5#28, change "Its type category is array" to "It is an array type".

In footnote 93 change "which removes any type qualifiers from the type category of the expression" to "which removes any type qualifiers from the outermost component of the type of the expression (for example, it removes const but not volatile from the type int volatile *const)".

In footnote 137 change the first part to:

The intent is that the fact that the identifier designates a function is shown explicitly and cannot be inherited from a typedef:

leaving the examples unchanged.


Comment from WG14 on 2003-10-06:

Committee Discussion (for history only)

The committee wishes to keep the term "type category" for now, removing the term "type category" from the next revision of the standard should be considered at that time. The text of footnote 93 does use the term incorrectly, but the wording can be changed to use the term correctly - and the parenthetical example provided in the DR can also be incorporated to make the intent even clearer.

Technical Corrigendum

Change footnote 93.

"...which removes any type qualifiers that were applied to the type category of the expression (for example, it removes const but not volatile from the type int volatile * const)."



Issue 0273: meaning of __STDC_ISO_10646__

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_273.htm

Problem

6.10.8 reads in part:

__STDC_ISO_10646__

An integer constant of the form yyyymmL (for example, 199712L), intended to indicate that values of type wchar_t are the coded representations of the characters defined by ISO/IEC 10646, along with all amendments and technical corrigenda as of the specified year and month.

Firstly, this wording is less than optimal, in that it could be read as making an implementation non-conforming if wchar_t has a value that does not correspond to an ISO 10646 (Unicode) character. Since Unicode has gaps in the encoding tables, this would mean that no implementation could define this symbol.

Secondly, is this wording meant to put a lower bound on the size of wchar_t, or does the (wchar_t = = Unicode) mapping only apply to those values that wchar_t can take. In other words, if a given version of Unicode defines characters up to U+12345, can WCHAR_MAX be less than 0x12345 on a system that defines this symbol ?

Suggested Technical Corrigendum

Replace the cited text by:

__STDC_ISO_10646__

An integer constant of the form yyyymmL (for example, 199712L). If this symbol is defined, then every character in the "Unicode required set", when stored in an object of type wchar_t, has the same value as the short identifier of that character.

and then either:

The "Unicode required set" consists of all the characters that are defined by ISO/IEC 10646, along with all amendments and technical corrigenda, as of the specified year and month.

if the intent is to put a minimum on the value of WCHAR_MAX, or then:

The "Unicode required set" consists of all the characters that:


Comment from WG14 on 2002-03-07:

Technical Corrigendum

Replace the relevant part of 6.10.8 with:

__STDC_ISO_10646__

An integer constant of the form yyyymmL (for example, 199712L). If this symbol is defined, then every character in the "Unicode required set", when stored in an object of type wchar_t, has the same value as the short identifier of that character. The "Unicode required set" consists of all the characters that are defined by ISO/IEC 10646, along with all amendments and technical corrigenda, as of the specified year and month.



Issue 0274: meaning of "character" in <string,h> functions

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_274.htm

Problem

7.21.2.1#2 defines the operation of memcpy as:

[#2] The memcpy function copies n characters from the object pointed to by s2 into the object pointed to by s1.

7.21.2.3#2 defines the operation of strcpy as:

[#2] The strcpy function copies the string pointed to by s2 (including the terminating null character) into the array pointed to by s1.

Other functions in 7.21 refer to either a string or a set of characters in the same way. The definition of "string" is in 7.1.1#1:

[#1] A string is a contiguous sequence of characters terminated by and including the first null character.

and that of "character" is in 3.7:

3.7 [#1] character
<abstract> member of a set of elements used for the organization, control, or representation of data

3.7.1 [#1] character single-byte character
<C> bit representation that fits in a byte

However, none of this makes it clear whether "character" is to be interpreted as having type char, signed char, or unsigned char. This matters because signed char need not have the same sized range of values as unsigned char (for example, SCHAR_MIN could be -127, or on a 10 bit byte system signed chars could have a padding bit, with SCHAR_MAX equal to 255 but UCHAR_MAX equal to 1023).

It would be very unfortunate if the mem* functions could not copy every possible byte value. The str* functions probably ought to access the values as if they were plain char.

Suggested Technical Corrigendum

Append a new paragraph to 7.21.1:

[#3] Where a block of characters is accessed through a parameter of type void *, each character shall be interpreted as if it had type unsigned char (and therefore every object representation is valid and has a different value). Where it is accessed through a parameter of type char *, each character shall be interpreted as if it had type char (and therefore, if CHAR_MAX - CHAR_MIN + 1 is less than UCHAR_MAX, some byte values may be trap representations or be treated as equal to other values).


Comment from WG14 on 2003-10-22:

Committee Discussion

Our intention is that string and memory copies in the standard library should be treated as unsigned char, similar to 7.21.4.

Technical Corrigendum

Add a new paragraph 7.21.1#3:

For all functions in this subclause, each character shall be interpreted as if it had the type unsigned char (and therefore every possible object representation is valid and has a different value).



Issue 0275: bitwise-OR of nothing

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_275.htm

Problem

FE_ALL_EXCEPT is defined in 7.6#6 as:

[#6] The macro

            FE_ALL_EXCEPT

is simply the bitwise OR of all floating-point exception macros defined by the implementation.

If no floating-point exception macros are defined, is FE_ALL_EXCEPT:

[This appears to be the only case of its kind.]

Suggested Technical Corrigendum

Append to 7.6#6:

If no such macros are defined, FE_ALL_EXCEPT can either be defined as 0 or left undefined.


Comment from WG14 on 2002-05-15:

Technical Corrigendum

Append to 7.6#6:

If no such macros are defined, FE_ALL_EXCEPT shall be defined as 0.



Issue 0276: orientation of perror

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Fixed
Fixed in: C99 TC2
Cross-references: 0322
Converted from: summary-c99.htm, dr_276.htm

Problem

The perror function (7.19.10.4) is not listed in 7.19.1 as either a byte input/output function or a wide character output function. I believe it should be the former.

Suggested Technical Corrigendum

In 7.19.1#5, fourth bullet, insert perror after gets.


Comment from WG14 on 2002-03-07:

Technical Corrigendum

In 7.19.1#5, fourth bullet, insert perror after gets.



Issue 0277: declarations within iteration statements

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Closed
Converted from: summary-c99.htm, dr_277.htm

Problem

Consider the code:

  for (enum fred { jim, sheila = 10 } i = jim; i < sheila; i++)
        // loop body

6.8.5#3 reads:

[#3] The declaration part of a for statement shall only declare identifiers for objects having storage class auto or register.

Does this wording forbid the declaration of tag fred - since it is not an object - or is fred not covered by that wording because it is not an object ?

Suggested Technical Corrigendum

Change 6.8.5#3 to one of:

[#3] The declaration part of a for statement shall only declare identifiers for objects; any object so declared shall have storage class auto or register.

or:

[#3] Any object whose identifier is declarared in the declaration part of a for statement shall have storage class auto or register.


Comment from WG14 on 2002-03-07:

Committee Response

The intent is clear enough; fred, jim, and sheila are all identifiers which do not denote objects with auto or register storage classes, and are not allowed in this context.



Issue 0278: lacuna in character encodings

Authors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_278.htm

Problem

Defect Report 091 discussed a multibyte character encoding where some single-byte characters are proper prefixes of two-byte characters. For example, single-byte characters have codes 1 to 127 while two-byte characters consist of such a code followed by a code from 128 to 255. At the time WG14 stated that such an encoding was legitimate.

Now 5.2.1.2 states, inter alia:

Nothing in this wording forbids a two-byte character from having a first byte that is zero. By the logic of DR091, just as the sequences 0x12 and 0x12 0x9A are both valid, but different, characters, so would the sequences 0x00 and 0x00 0x9A; the first would be the null character and the second would be something else. Note that there are no shift states, and so the wording "independent of shift state" is irrelevant.

This interpretation is undesirable for obvious reasons, and so it ought to be outlawed.

Suggested Technical Corrigendum

Replace the current last two bullets with a single one:


Comment from WG14 on 2002-03-07:

Technical Corrigendum

Replace the current last two bullets in 5.2.1.2 with a single bullet:



Issue 0279: Wide character code values for members of the basic character set

Authors: J11, Raymond Mak (US)
Date: 2001-10-18
Reference document: ISO/IEC WG14 N956
Status: Fixed
Fixed in: C99 TC2
Cross-references: 0321
Converted from: summary-c99.htm, dr_279.htm

Summary

Standard C requires ('x' == L'x') to hold true if x is a member of the basic character set. This restricts the implementation's choice of wchar_t encoding. The restriction makes it very difficult, if not impossible, for EBCDIC based system to use Unicode as the wchar_t encoding.

Note: For the purpose of this DR, we will call this restriction the wchar_t restriction.

Details

C99 7.17 paragraph 2 specifies in part:

"...

   wchar_t

which is an integer type whose range of values can represent distinct codes for all members of the largest extended character set specified among the supported locales; the null character shall have the code value zero and each member of the basic character set shall have a code value equal to its value when used as the lone character in an integer character constant."

Since the code value of the basic characters in UCS-2 and UCS-4 are based on ASCII, EBCDIC systems cannot conform to the last sentence of the above if the encoding of wchar_t is UCS-2 or UCS-4. This makes it unnecessarily difficult for EBCDIC systems to use Unicode with the C language.

A program knows the type of characters (wide or normal) it is processing. Therefore the appropriate character literal can always be used in an expression. In situations where a program does need to mix normal and wide character code values, the btowc and wctob functions should be used (7.24.6.1 and .2). Facilitating such mixing were the original reason for imposing the wchar_t restriction in C90. With the introduction of these two functions in Amendment 1, this restriction can be relaxed with little practical impact to the programmer.

Suggested Technical Corrigendum

Suggestion 1

This change allows an implementation to deviate from the last part of 7.17 paragraph 2 if the macro __STDC_BTOWC_NEQ_WCTOB__ is predefined. This would not affect ASCII based systems, but would provide leeway for EBCDIC systems to process Unicode using C.

Change the last part of 7.17 paragraph 2 as follows:

"...

   wchar_t

which is an integer type whose range of values can represent distinct codes for all members of the largest extended character set specified among the supported locales; the null character shall have the code value zero. Each member of the basic character set shall have a code value equal to its value when used as the lone character in an integer character constant if an implementation does not define __STDC_BTOWC_NEQ_WCTOB__."

A program that requires the wchar_t restriction can check for the macro and cause the translator to put out a diagnostic if the implementation does not support the restriction. This at least would help diagnose porting problems.

Suggestion 2

This change removes the restriction altogether.

Change the last part of 7.17 paragraph 2 as follows:

"...

   wchar_t

which is an integer type whose range of values can represent distinct codes for all members of the largest extended character set specified among the supported locales; the null character shall have the code value zero."

Suggestion 3

This change reverses the meaning of the macro in suggestion 1 and combine with the text in suggestion 2. An implementation can assert conformance to the wchar_t restriction by defining the macro __STDC_BTOWC_EQ_WCTOB__.

Note: Despite what the macro name suggests, btowc and wctob may not be the same disregard of the mapping of the basic character set because of EOF/WEOF.

Change the last part of 7.17 paragraph 2 as follows:

"...

   wchar_t

which is an integer type whose range of values can represent distinct codesfor all members of the largest extended character set specified among thesupported locales; the null character shall have the code value zero."

Add the following paragraph to 7.24.1 after #3.

"The macro __STDC_BTOWC_EQ_WCTOB__ is defined if the implementation intends to assert that for each member of the basic character set the wchar_t encoding has a code value equal to its value when used as the lone character in an integer character constant."


Comment from WG14 on 2002-05-15:

Technical Corrigendum

Change the last part of 7.17 paragraph 2 as follows:

"...

   wchar_t

which is an integer type whose range of values can represent distinct codes for all members of the largest extended character set specified among the supported locales; the null character shall have the code value zero."



Issue 0280: struct tm, member tm_isdst, and mktime() in <time.h>

Authors: Emmanuel Ruffin (ruffin@besancon.sema.slb.com) via ANSI, Randy Meyers (US)
Date: 2002-09-26
Status: Closed
Converted from: summary-c99.htm, dr_280.htm

Summary

If it is not known whether daylight saving time is in effect (tm_isdst set to -1), some times expressed in struct tm become ambiguous. There is no specification as to what mktime() should do for such cases.

Questions

  1. Normally when calling mktime(), the user will set tm_isdst to -1 to request that mktime() determine the true value (See 7.23.2.3 footnote 267). Usually, mktime() can determine whether daylight saving time is in effect based on the time and date information initially stored in the struct tm argument. However, during the Fall change over, there is one hour that exists both in daylight saving time and standard time. Example: In France, we will change time on October the 27th at 3am. That means that at 3am it will be 2am again. If asked to convert October 27 at 2.30am when tm_isdst is -1, what value should mktime() store in tm_isdst and what is the return value?
  2. For the same example as point 1, what should we return in case tm_isdst is set to 0 or 1 ?
  3. In a general case, what should we do in case tm_isdst is different from -1 ?
  4. When calling mktime() function, is it true that this function should modify the tm structure to put in it the GM time instead the local time given as an entry ?

Suggested Committee Response

Subclause 7.23.1 Paragraph 1 of the C Standard says,

"The local time zone and Daylight Saving Time are implementation-defined."

That means that the standard does not specify the behavior and that the implementation is free to make choices that it must document. Although the C Standard imposes no particular definition on daylight saving time, other standards or local custom may.

  1. It is implementation defined. For example, an implementation might assume that daylight saving time is not in effect and set tm_isdst to 0 and return the time_t value corresponding to 2:30 AM Standard Time.
  2. It is implementation defined. However, assuming that an implementation chose a conventional definition of daylight saving time, these times are unambiguous since the user specified whether daylight saving time was in effect, and the time_t return value would be different for 2:30 daylight saving time versus 2:30 standard time. Note that it would be reasonable for mktime() to change tm_hour and tm_isdst on output. For example, tm_hour=2 and tm_isdst=1 on input might change to tm_hour=1 and tm_dst=0 on output.
  3. It is implementation defined. One possibility would be to consider any two struct tm values as being exactly one hour apart if all members have the same value except that one struct tm value has tm_isdst=1 and the other has tm_isdst=0 (regardless of the date stored in the struct tm values).
  4. No. A struct tm represents a local time in the local time zone for mktime(). See 7.23.2.3 Paragraph 2.

Comment from WG14 on 2003-10-06:

Committee Response

It is implementation defined. One possibility would be to consider any two struct tm values as being exactly one hour apart if all members have the same value except that one struct tm value has tm_isdst=1 and the other has tm_isdst=0 (regardless of the date stored in the struct tm values).

See footnote 267.



Issue 0281: CLOCKS_PER_SEC should not be a constant expression

Authors: Convener, J. Benito (convener)
Date: 2002-06-06
Reference document: ISO/IEC WG14 N982
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_281.htm

Summary

In 7.23.1 Components of time, CLOCKS_PER_SEC is defined as a macro which expands to a constant expression with type clock_t. CLOCKS_PER_SEC need not be a compile time constant expression, but should be a runtime constant. A value that is unchanged during program execution.

Suggested Technical Corrigendum


Comment from WG14 on 2003-03-06:

Technical Corrigendum

In 7.23.1 Components of time, remove the word "constant" in the 2nd paragraph.



Issue 0282: flexible array members & struct padding

Authors: J11, Douglas Walls (US)
Date: 2002-06-11
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_282.htm

Summary

6.7.2.1 Structure and union specifiers, paragraphs 15 and 16 require that any padding for
alignment of a structure containing a flexible array member must preceed the flexible
array member.  This contradicts existing implementations.  We do not believe this was the intent of the C99 specification.

Details

If a struct contains a flexible array member and also requires padding for alignment, then the current C99 specification requires the implementation to put this padding before the flexible array member.  However, existing implementations, including at least GNU C, Compaq C, and Sun C, put the padding after the flexible array member.

The layout used by existing implementations can be more efficient. Furthermore, requiring these existing implementations to change their layout would break binary backwards compatibility with previous versions.

Suggested Technical Corrigendum

Change the wording such that it is implementation defined as to whether the padding is before or after the flexible array member.


Comment from WG14 on 2004-03-06:

Technical Corrigendum

In 6.7.2.1 paragraph 16, replace the second and third sentences ("With two ... 106)" with the following text:.

In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply.

replace "Second" with "However" at the start of the following sentence, and delete footnote 106.

Replace the examples (paragraphs 17 to 20) with:

[#17] EXAMPLE After the declaration:

            struct s { int n; double d[]; };

the structure struct s has a flexible array member d. A typical way to use this is:

           int m = /* some value */;
            struct s *p = malloc (sizeof (struct s) + sizeof (double [m]));

and assuming that the call to malloc succeeds, the object pointed to by p behaves, for most purposes, as if p had been declared as:

            struct { int n; double d[m]; } *s1;

(there are circumstances in which this equivalence is broken; in particular, the offsets of member d might not be the same).

[#18] Following the above declaration:

            struct s t1 = { 0 };           // valid
            struct s t2 = { 1, { 4.2 }};   // invalid
            t1.n = 4;                      // valid
            t1.d[0] = 4.2;                 // might be undefined behavior

The initialization of t2 is invalid (and violates a constraint) because struct s is treated as if it does not contain member d. The assigment to t1.d[0] is probably undefined behaviour, but it is possible that

            sizeof (struct s) >= offsetof (struct s, d) + sizeof (double)

in which case the assignment would be legitimate. Nevertheless it cannot appear in strictly conforming code.

[#19] After the further declaration:

            struct ss { int n; };

the expressions:

            sizeof (struct s) >= sizeof (struct ss)
            sizeof (struct s) >= offsetof (struct s, d)

are always equal to 1.

[#20] If sizeof (double) is 8, then after the following code is executed:

            struct s *s1;
            struct s *s2;
            s1 = malloc(sizeof (struct s) + 64);
            s2 = malloc(sizeof (struct s) + 46);

and assuming that the calls to malloc succeed, the objects pointed to by s1 and s2 behave, for most purposes, as if the identifiers had been declared as:

            struct { int n; double d[8]; } *s1;
            struct { int n; double d[5]; } *s2;

[#21] Following the further successful assignments:

            s1 = malloc(sizeof (struct s) + 10);
            s2 = malloc(sizeof (struct s) +  6);

they then behave as if the declarations were:

            struct { int n; double d[1]; } *s1, *s2;

and:

            double *dp;
            dp = &(s1->d[0]);       // valid
            *dp = 42;               // valid
            dp = &(s2->d[0]);       // valid
            *dp = 42;               // undefined behavior

[#22] The assignment:

            *s1 = *s2;

only copies the member n; if any of the array elements are within the first sizeof (struct s) bytes of the structure, these might be copied or simply overwritten with indeterminate values.



Issue 0283: Accessing a non-current union member ("type punning")

Authors: J11, Clark Nelson
Date: 2002-09-18
Status: Fixed
Fixed in: C99 TC3
Cross-references: 0257
Converted from: summary-c99.htm, dr_283.htm

[This report isolates one of the points from DR257.]

Problem

In the paragraph corresponding to 6.5.2.3#5, C89 contained this sentence:

With one exception, if a member of a union object is accessed after a value has been stored in a different member of the object, the behavior is implementation-defined.

Associated with that sentence was this footnote:

The "byte orders" for scalar types are invisible to isolated programs that do not indulge in type punning (for example, by assigning to one member of a union and inspecting the storage by accessing another member that is an appropriately sixed array of character type), but must be accounted for when conforming to externally imposed storage layouts.

The only corresponding verbiage in C99 is 6.2.6.1#7:

When a value is stored in a member of an object of union type, the bytes of the object representation that do not correspond to that member but do correspond to other members take unspecified values, but the value of the union object shall not thereby become a trap representation.

It is not perfectly clear that the C99 words have the same implications as the C89 words.

Suggested Technical Corrigendum

[Essentially verbatim from DR257]

Attach a new footnote 78a to the words "named member" in 6.5.2.3#3:

78a If the member used to access the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called "type punning"). This might be a trap representation.


Comment from WG14 on 2004-09-28:

Technical Corrigendum

Attach a new footnote 78a to the words "named member" in 6.5.2.3#3:

78a If the member used to access the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called "type punning"). This might be a trap representation.



Issue 0284: Does <math.h> define INT_MIN and INT_MAX?

Authors: J11, Douglas Walls (US)
Date: 2003-02-11
Reference document: ISO/IEC WG14 N995
Status: Closed
Converted from: summary-c99.htm, dr_284.htm

Summary

<math.h> defines macros in terms of INT_MIN and INT_MAX. <math.h> defines functions returning the value of INT_MIN. It is unclear if inclusion of <math.h> defines INT_MIN and INT_MAX or also includes <limits.h>.

Details

The description of <math.h> in C99 (section 7.12) says that the macros FP_ILOGB0 and FP_ILOGBNAN are defined in <math.h> with values, respectively INT_MIN or -INT_MAX and INT_MAX or INT_MIN, but never says that INT_MIN and INT_MAX are defined in <math.h>.

The synopsis of 7.12.6.5 The ilogb function says:

        #include <math.h>
        int ilogb(double x);
        int ilogbf(float x);
        int ilogbl(long double x);

The description of 7.12.6.5 The ilogb functions says "if x is infinite they compute the value INT_MAX;".

Does this mean that <math.h> includes <limits.h>?

Does this mean that <math.h> defines INT_MIN and INT_MAX?

Suggested Technical Corrigendum


Comment from WG14 on 2004-03-05:

Committee Response

No Standard library header includes another Standard library header. The header <math.h> does not define INT_MIN or INT_MAX. A program that wants to check the return value for equality with one of these macros must include <limits.h>.



Issue 0285: Conversion of an imaginary type to _Bool

Authors: WG14 Convener
Date: 2003-02-26
Reference document: ISO/IEC WG14 N1002
Status: Fixed
Fixed in: C99 TC2
Cross-references: 0447
Converted from: summary-c99.htm, dr_285.htm

Summary

6.3.1.2 is clear that any non-zero scalar value gets turned into 1 by a _Bool conversion.

However, G.4.2 says that when an imaginary value is converted to a real, the result is zero.

Suggested Technical Corrigendum

Change G.4.2 to:

When a value of imaginary type is converted to a real type other than _Bool, the result is a positive zero. See 6.3.1.2.


Comment from WG14 on 2004-03-17:

Technical Corrigendum

Change G.4.2 to:

When a value of imaginary type is converted to a real type other than _Bool, the result is a positive zero. See 6.3.1.2.



Issue 0286: Correctly rounded and rounding direction/mode

Authors: WG 14, Fred Tydeman (USA)
Date: 2003-04-13
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_286.htm

Summary

Three 'equivalent' phrases are used:

    effective rounding
    current rounding
    rounding mode characterized by the value of FLT_ROUNDS

when C99 should be using just one.

Six 'equivalent' phrases are used:

    rounding direction mode
    rounding direction
    rounding mode
    directed-rounding control mode
    directed rounding mode
    rounding control mode

when C99 should be using just one.

Details

3.9 correctly rounded result: representation in the result format that is nearest in value, subject to the effective rounding mode, to what the result would be given unlimited range and precision

5.2.4.2.2 Characteristics of floating types <float.h>: Paragraph 6: The rounding mode for floating-point addition is characterized by the implementation-defined value of FLT_ROUNDS:18)

18) Evaluation of FLT_ROUNDS correctly reflects any execution-time change of rounding mode through the function fesetround in <fenv.h>.

7.6 Floating-point environment <fenv.h>:

Paragraph 1: The header <fenv.h> declares two types and several macros and functions to provide access to the floating-point environment. The floating-point environment refers collectively to any floating-point status flags and control modes supported by the implementation.173)

173) This header is designed to support the floating-point exception status flags and directed-rounding control modes required by IEC 60559, and other similar floating-point state information.

Paragraph 7 Each of the macros: FE_DOWNWARD, FE_TONEAREST, FE_TOWARDZERO, FE_UPWARD; is defined if and only if the implementation supports getting and setting the represented rounding direction by means of the fegetround and fesetround functions.

7.6.3 Rounding: Paragraph 1 The fegetround and fesetround functions provide control of rounding direction modes.

7.12.9.3 The nearbyint functions: Paragraph 2: The nearbyint functions round their argument to an integer value in floating-point format, using the current rounding direction and without raising the inexact floating-point exception.

7.12.9.5 The lrint and llrint functions: Paragraph 2: The lrint and llrint functions round their argument to the nearest integer value, rounding according to the current rounding direction.

7.12.9.6 The round functions: Paragraph 2: The round functions round their argument to the nearest integer value in floating-point format, rounding halfway cases away from zero, regardless of the current rounding direction.

7.12.9.7 The lround and llround functions: Paragraph 2: The lround and llround functions round their argument to the nearest integer value, rounding halfway cases away from zero, regardless of the current rounding direction.

Footnote 203) When y != 0, the remainder r = x REM y is defined regardless of the rounding mode ...

7.12.13.1 The fma functions: Paragraph 2: The fma functions compute (x*y)+z, rounded as one ternary operation: they compute the value (as if) to infinite precision and round once to the result format, according to the rounding mode characterized by the value of FLT_ROUNDS.

7.19.6.1 The fprintf function:

Paragraph 12: ... error should have a correct sign for the current rounding direction.

Paragraph 13: ... error should have a correct sign for the current rounding direction.

7.20.1.3 The strtod, strtof, and strtold functions:

Paragraph 8: ... error should have a correct sign for the current rounding direction.

Paragraph 9: ... according to the current rounding direction, ... ... should have a correct sign for the current rounding direction.

7.24.2.1 The fwprintf function:

Paragraph 12: ... error should have a correct sign for the current rounding direction.

Paragraph 13: ... the error should have a correct sign for the current rounding direction.

7.24.4.1.1 The wcstod, wcstof, and wcstold functions:

Paragraph 8: ... the error should have a correct sign for the current rounding direction.

Paragraph 9: ... according to the current rounding direction, with the extra stipulation that the error with respect to D should have a correct sign for the current rounding direction.

Annex F.3 Operators and functions: Paragraph 1: The fegetround and fesetround functions in <fenv.h> provide the facility to select among the IEC 60559 directed rounding modes represented by the rounding direction macros in <fenv.h> (FE_TONEAREST, FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO) and the values 0, 1, 2, and 3 of FLT_ROUNDS are the IEC 60559 directed rounding modes.

Annex F.5 Binary-decimal conversion:

Paragraph 2: Conversions involving IEC 60559 formats follow all pertinent recommended practice. In particular, conversion between any supported IEC 60559 format and decimal with DECIMAL_DIG or fewer significant digits is correctly rounded, which assures that conversion from the widest supported IEC 60559 format to decimal with DECIMAL_DIG digits and back is the identity function.

Paragraph 3: 3 Functions such as strtod that convert character sequences to floating types honor the rounding direction. Hence, if the rounding direction might be upward or downward, the implementation cannot convert a minus-signed sequence by negating the converted unsigned sequence.

Annex F.6 Contracted expressions: Paragraph 1: A contracted expression treats infinities, NaNs, signed zeros, subnormals, and the rounding directions in a manner consistent with the basic arithmetic operations covered by IEC 60559.

Annex F.7 Floating-point environment: Paragraph 1: The floating-point environment defined in <fenv.h> includes the IEC 60559 floating-point exception status flags and directed-rounding control modes.

Annex F.7.1 Environment management: Paragraph 1: IEC 60559 requires that floating-point operations implicitly raise floating-point exception status flags, and that rounding control modes can be set explicitly to affect result values of floating-point operations.

Annex F.7.2 Translation: Paragraph 1: During translation the IEC 60559 default modes are in effect: The rounding direction mode is rounding to nearest.

Footnote 306) As floating constants are converted to appropriate internal representations at translation time, their conversion is subject to default rounding modes ...

Annex F.7.3 Execution: Paragraph 1: At program startup the floating-point environment is initialized as prescribed by IEC 60559: All floating-point exception status flags are cleared. The rounding direction mode is rounding to nearest.

Footnote 307) Where the state for the FENV_ACCESS pragma is "on", results of inexact expressions like 1.0/3.0 are affected by rounding modes set at execution time, ...

Annex F.8.2 Expression transformations: has in several places: default rounding direction.

Annex F.8.4 Constant arithmetic: Paragraph 1: ... changing the rounding direction to downward ...

Footnote 311) 0-0 yields -0 instead of +0 just when the rounding direction is downward.

Annex F.9 Mathematics <math.h>:

Paragraph 6: ... rounding direction, ...

Paragraph 10: Whether the functions honor the rounding direction mode is implementation-defined.

Annex F.9.6.3 The nearbyint functions: Paragraph 1: The nearbyint functions use IEC 60559 rounding according to the current rounding direction.

Annex F.9.6.5 The lrint and llrint functions: Paragraph 1: The lrint and llrint functions provide floating-to-integer conversion as prescribed by IEC 60559. They round according to the current rounding direction.

Annex F.9.6.7 The lround and llround functions: Paragraph 1: The lround and llround functions differ from the lrint and llrint functions with the default rounding direction ...

Annex F.9.6.8 The trunc functions: Paragraph 1: The trunc functions use IEC 60559 rounding toward zero (regardless of the current rounding direction).

Annex J.3.6 Floating point: Paragraph 1: Additional floating-point exceptions, rounding modes, environments, and classifications, and their macro names (7.6, 7.12).

Annex J.3.12 Library functions: Whether the functions in <math.h> honor the rounding direction mode in an IEC 60559 conformant implementation (F.9).

Index:

correctly rounded result, 3.9

floating-point rounding mode, 5.2.4.2.2

rounding mode, floating point, 5.2.4.2.2

Suggested Technical Corrigendum

Of the six 'equivalent' phrases that involve 'rounding', 'direction', 'control', and 'mode', pick one ('rounding mode' is the submitter's choice) and change the others to it thruout the C99 standard.

Change 3.9 'effective rounding mode' to 'current rounding mode'.

Change 7.12.13.1 The fma functions: '... the rounding mode characterized by the value of FLT_ROUNDS' to '... the current rounding mode'.

Change Annex F.5 Binary-decimal conversion: Paragraph 2: 'correctly rounded' to 'correctly rounded (which honors the current rounding mode)'. Note: Once 'effective rounding mode' is changed to 'current rounding mode', is this change really needed (since correctly rounded implies honors the current rounding mode)?


Comment from WG14 on 2004-09-28:

Committee Discussion

This needs to be passed by the original authors to see if there is some rationale for the multiple terminology. No real opposition to the Suggested Technical Corrigendum, the Committee does not feel a need to rush this change.

Technical Corrigendum

Change 3.9 'effective rounding mode' to 'current rounding mode'.

Change 7.12.13.1 The fma functions: '... the rounding mode characterized by the value of FLT_ROUNDS' to '... the current rounding mode'.

Change Annex F.5 Binary-decimal conversion: Paragraph 2: 'correctly rounded' to 'correctly rounded (which honors the current rounding mode)'.



Issue 0287: Floating-point status flags and sequence points

Authors: WG 14, Fred Tydeman (USA)
Date: 2003-04-13
Reference document: ISO/IEC WG14 C90 DR 087
Status: Fixed
Fixed in: C99 TC3
Cross-references: 0087
Converted from: summary-c99.htm, dr_287.htm

Summary

The problem is, 6.5 Expressions (which existed in C90) was not updated when the floating-point status flags were added to C99. Also, the response to C90 DR 087 was not incorporated into C99.

Consider the expression: a = x*y + w*z; where all variables are of type double and each of the sub-expressions x*y and w*z raises the floating-point overflow exception, which sets the floating-point overflow status flag as a side-effect. The model used by C99 (5.1.2.3 Program execution, in particular, paragraph 2 and footnote 11; as well as, 7.6 Floating-point environment <fenv.h>, in particular, paragraph 1; 7.6.2 Floating-point exceptions; and F.7.1 Environment management) and IEC 60599 / IEEE-754 is that the status flags are sticky and may be set multiple times as side effects of floating-point operations between sequence points. Setting the same floating-point status flag multiple times is well defined: it is set.

Consider the expression: b = (feclearexcept)(FE_OVERFLOW) + (feraiseexcept)(FE_OVERFLOW); which both clears and sets the same floating-point status flag between two sequence points by the use of functions (not macros). If the execution of the two functions is allowed to overlap, then this is undefined behaviour (as the same object is being modified to two different values at the "same" time (between the same pair of sequence points)). If functions are atomic (not allowed to overlap execution), then, each function evaluation is considered a sequence point, and the two modifies are not between the same two sequence points. That means, there is no undefined behaviour, but it is unspecified as to which of the two function calls is done first/last. I understand that draft C89 had words similar to "Function calls are allowed to overlap.", but that they were removed before C89 became a standard, and that only those who know that bit of history know that C99 does not allow functions to overlap execution. C90 Defect Report 087 had as part of its response "function calls do not overlap", but those words are not in C99.

The same problem exists for ERRNO. Consider the expression: b = (log)(-1.0) + (exp)(DBL_MAX); in which log sets errno to EDOM, while exp sets errno to ERANGE.

Modifying the same status flag twice between two sequence points is a direct contradiction of 6.5 Expressions, paragraph 2: "Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression." C99 needs to allow for multiple updates to the same floating-point status flag.

Suggested Technical Corrigendum

Add to 6.5 Expressions, paragraph 2, after the first sentance: An exception to this shall be permitted if the object is a floating-point status flag and the modification sets the flag.

Add to 6.5 Expressions, paragraph 3, after the last sentance: Function calls, in the same expression-statement, do not overlap. Another possible place to add this could be 6.5.2.2 Function calls, paragraph 10. Possible wording issue: recursive function calls.


Comment from WG14 on 2006-03-29:

Committee Discussion

Flags are not objects, thus the constraint on modifying objects doesn't apply to flags.

Committee Response

As noted in the response to DR 087, function calls in the same expression do not overlap. This has not changed for C99.

Technical Corrigendum

Add a footnote to 6.5 Expressions, paragraph 2, after the first sentence.

*A floating-point status flag is not an object and can be set more than once within an expression.

Add a footnote to 7.6 Floating-point environment, paragraph 1, after the third sentence.

*A floating-point status flag is not an object and can be set more than once within an expression.



Issue 0288: deficiency on multibyte conversions

Authors: BSI, Clive Feather
Date: 2003-10-21
Reference document: N1012
Status: Closed
Converted from: summary-c99.htm, dr_288.htm

Summary

Consider a typical use of the multibyte conversion function mbrtowc:

    enum { FINISHED, ERROR } convert (void)
    {
        mbstate_t s = { 0 };
        char c;
        wchar_t wc;

        for (;;)
        {
            c = get_a_byte ();
            switch (mbrtowc (&wc, &c, 1, &s))
            {
            case 1:          put_wide_char (wc);    break;
            case (size_t)-2: break;
            case 0:          put_wide_char (L'\0'); return FINISHED;
            case (size_t)-1: return ERROR;
            }
        }
    }

The multibyte conversion functions were originally written on the assumption that wide characters are singletons. That is, while several multibyte characters may map to one wide character, and may map to different wide characters depending on the current state, each sequence maps to only one wide character. As a result, functions such as mbrtowc do not have the concept of returning more than one wide character; only a single one can be returned per call.

This is fine for mappings like:

    ISO 8859-1   ->  UTF-16 or UTF-32 in Normalization Form C
    UTF-8        ->  UTF-32 without change of normalization

but not for others. It is possible to play fast and loose with the meaning of state to relax the requirement a little bit - if a sequence of three bytes maps to two wide characters, the first call to mbrtowc can return 2 and the second call 1, with the state object holding any necessary information. The requirement then becomes: N bytes can result in M wide characters, where N >= M and where the first K wide characters depend only on the first N-M+K bytes. An example of such a mapping is UTF-8 -> UTF-16 (shown in binary):

  0AAAAAAA                            -> 000000000AAAAAAA
  110AAAAA 10BBBBBB                   -> 00000AAAAABBBBBB
  1110AAAA 10BBBBBB 10CCCCCC          -> AAAABBBBBBCCCCCC
  11110AAA 10BBCCCC 10DDEEEE 10FFFFFF -> 110110XXXXCCCCDD
110111EEEEFFFFFF

In the last case the mbrtowc function can return -2, -2, 1, and 1 in that order. However, consider a very similar encoding to UTF-16 where the two wide characters are in the opposite order. The first wide character (the one beginning 110111) cannot be output until all 4 bytes have been seen, so the first three calls to mbrtowc must return -2. The fourth call can return the first wide character, but there is now no way to return the second one. If the next UTF-8 sequence is 2 or 3 bytes long, it would provide an opportunity, but if it is only 1 byte long or, even worse, was the zero character, it wouldn't. While the above is a hypothetical situation, a real conversion that has this problem is converting ISO 8859-1 (or many similar encodings) to Unicode in Normalization Form D. In NFD all accented characters are broken down into their components. So some example conversions are:

    0x20 -> 0x0020
    0x61 -> 0x0061
    0xBF -> 0x00BF
    0xC0 -> 0x0041 0x0300
    0xC1 -> 0x0041 0x0301
    0xC4 -> 0x0041 0x0308
    0xC8 -> 0x0045 0x0300
    0xE6 -> 0x00E6
    0xE7 -> 0x0063 0x0327

What is needed is for mbrtowc to have a way to say "I have an unfinished wide character sequence, I do not need any more bytes for now". The obvious way to represent this would be a returned value of 0. Unfortunately this has already been given a different meaning ("end of string reached") and changing it would be impractical. Therefore the following text proposes the return value -3 for this case. This value would only be generated for locales where this was an issue, so it will not affect existing uses of the code. And applications that are not modified to handle this code but are presented with it are likely to treat it as an error.

Of the other functions in 7.24.6, mbrlen has the same problem. The wcrtomb function also has to deal with this issue, but the wording already allows it to be state-ful and return 0 to indicate that nothing has been output at this stage. Neither the mbsrtowcs nor wcsrtombs functions have an issue (though with the former it is possible that the limit of len wide characters is reached in the middle of a multi-wide-character sequence; the rest of the sequence will be retained in the mbstate_t object until the next call).

Suggested Technical Corrigendum

Append to 7.24.6.3.2#4:

(size_t)(-3) if the multibyte sequence converted by the previous call with the same mbstate_t object generated more than one wide character and not all these characters have yet been stored; the next wide character in the sequence has now been stored and no bytes from the input have been consumed by this call.

In 7.24.6.3.1#3, add (size_t)(-3) to the possible returned values.

Optional extra change for clarity:

In 7.24.6.3.3#4, EITHER add to the end of the first sentence:

; this may be 0

OR add a footnote reference to that sentence:

291A If the wide character encoding requires two or more wide characters to be considered together when doing the conversion, the value returned can be 0.

The Rationale could also be amended to address these issues.


Comment from WG14 on 2004-09-28:

Committee Discussion

Committee Response

This is not really a defect, but a deficiency which could be addressed in a future release of the C Standard.



Issue 0289: Function prototype with [restrict]

Authors: The Open Group, Andrew Josey via Fred Tydeman
Date: 2003-08-15
Reference document: Open Group aardvark 117
Status: Fixed
Fixed in: C99 TC3
Cross-references: 1002
Converted from: summary-c99.htm, dr_289.htm

Summary

6.7.6 (direct-abstract-declarator) is inconsistent with 6.7.5 (direct-declarator) with respect to omitting an identifier from a declaration to form a type name.

Here is a specific example that shows the problem.

 int lio_listio(int, struct aiocb *restrict const[restrict]);

is invalid and appears to have to be done as:

 int lio_listio(int, struct aiocb *restrict const __FOO[restrict]);

6.7.6 Type names, paragraph 2 has:

In several contexts, it is necessary to specify a type. This is accomplished using a type name, which is syntactically a declaration for a function or an object of that type that omits the identifier.

So you would think that if

  struct aiocb *restrict const __FOO[restrict]

is a valid declaration of the object __FOO, then it should follow from the above statement that

  struct aiocb *restrict const [restrict]

must be a valid type name.


Comment from WG14 on 2004-03-03:

Technical Corrigendum

In the syntax rules for direct-abstract-declarator in 6.7.6 paragraph 1, replace

direct-abstract-declaratoropt [ assignment-expressionopt ]

with

direct-abstract-declaratoropt [ type-qualifier-listopt assignment-expressionopt ]

direct-abstract-declaratoropt [ static type-qualifier-listopt assignment-expression ]

direct-abstract-declaratoropt [ type-qualifier-list static assignment-expression ]



Issue 0290: FLT_EVAL_METHOD and extra precision and/or range

Authors: WG 14, Fred Tydeman (USA)
Date: 2003-08-29
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_290.htm

Summary

FLT_EVAL_METHOD says that all floating-point operations and operands are evaluated to a format whose range and precision may be greater than required by the type. This contradicts descriptions of assignment and cast. It may contradict return. It may contradict argument passing. It may contradict register variables.

Details from C99+TC1

5.2.4.2.2 Characteristics of floating types <float.h>

7 The values of operations with floating operands and values subject to the usual arithmetic conversions and of floating constants are evaluated to a format whose range and precision may be greater than required by the type. The use of evaluation formats is characterized by the implementation-defined value of FLT_EVAL_METHOD:19)

-1 indeterminable;

0 evaluate all operations and constants just to the range and precision of the type;

1 evaluate operations and constants of type float and double to the range and precision of the double type, evaluate long double operations and constants to the range and precision of the long double type;

2 evaluate all operations and constants to the range and precision of the long double type.

All other negative values for FLT_EVAL_METHOD characterize implementation-defined behavior.

19) The evaluation method determines evaluation formats of expressions involving all floating types, not just real types. For example, if FLT_EVAL_METHOD is 1, then the product of two float _Complex operands is represented in the double _Complex format, and its parts are evaluated to double.

5.1.2.3 Program Execution

12 EXAMPLE 4 Implementations employing wide registers have to take care to honor appropriate semantics. Values are independent of whether they are represented in a register or in memory. For example, an implicit spilling of a register is not permitted to alter the value. Also, an explicit store and load is required to round to the precision of the storage type. In particular, casts and assignments are required to perform their specified conversion. For the fragment

                double d1, d2;
                float f;
                d1 = f = expression;
                d2 = (float)expressions;

the values assigned to d1 and d2 are required to have been converted to float.

6.3 Conversions

1 Several operators convert operand values from one type to another automatically. This subclause specifies the result required from such an implicit conversion, as well as those that result from a cast operation (an explicit conversion). The list in 6.3.1.8 summarizes the conversions performed by most ordinary operators; it is supplemented as required by the discussion of each operator in 6.5.

6.3.1.5 Real floating types

1 When a float is promoted to double or long double, or a double is promoted to long double, its value is unchanged.

2 When a double is demoted to float, a long double is demoted to double or float, or a value being represented in greater precision and range than required by its semantic type (see 6.3.1.8) is explicitly converted to its semantic type, if the value being converted can be represented exactly in the new type, it is unchanged. If the value being converted is in the range of values that can be represented but cannot be represented exactly, the result is either the nearest higher or nearest lower representable value, chosen in an implementation-defined manner. If the value being converted is outside the range of values that can be represented, the behavior is undefined.

6.3.1.8 Usual Arithmetic Conversions

2 The values of floating operands and of the results of floating expressions may be represented in greater precision and range than that required by the type; the types are not changed thereby.52)

52) The cast and assignment operators are still required to perform their specified conversions as described in 6.3.1.4 and 6.3.1.5.

6.5.4 Cast operators

Semantics

4 Preceding an expression by a parenthesized type name converts the value of the expression to the named type. This construction is called a cast.85) A cast that specifies no conversion has no effect on the type or value of an expression.86)

86) If the value of the expression is represented with greater precision or range than required by the type named by the cast (6.3.1.8), then the cast specifies a conversion even if the type of the expression is the same as the named type.

6.5.2.2 Function calls

Semantics

4 An argument may be an expression of any object type. In preparing for the call to a function, the arguments are evaluated, and each parameter is assigned the value of the corresponding argument.78)

6.9.1 Function definitions

Semantics

10 On entry to the function, the size expressions of each variably modified parameter are evaluated and the value of each argument expression is converted to the type of the corresponding parameter as if by assignment. (Array expressions and function designators as arguments were converted to pointers before the call.)

6.8.6.4 The return statement

Semantics

3 If a return statement with an expression is executed, the value of the expression is returned to the caller as the value of the function call expression. If the expression has a type different from the return type of the function in which it appears, the value is converted as if by assignment to an object having the return type of the function.136)

136) The return statement is not an assignment. The overlap restriction of subclause 6.5.16.1 does not apply to the case of function return.

6.7.1 Storage-class specifiers

Semantics

4 A declaration of an identifier for an object with storage-class specifier register suggests that access to the object be as fast as possible. The extent to which such suggestions are effective is implementation-defined.100)

100) The implementation may treat any register declaration simply as an auto declaration. However, whether or not addressable storage is actually used, the address of any part of an object declared with storage-class specifier register cannot be computed, either explicitly (by use of the unary & operator as discussed in 6.5.3.2) or implicitly (by converting an array name to a pointer as discussed in 6.3.2.1). Thus, the only operator that can be applied to an array declared with storage-class specifier register is sizeof.

Suggested Technical Corrigendum

In 5.2.4.2.2 Characteristics of floating types <float.h>, change paragraph 7 to:

Except for assignment and cast (which remove all extra range and precision), the values of operations with floating operands and values subject to the usual arithmetic conversions and of floating constants are evaluated to a format whose range and precision may be greater than required by the type. The use of evaluation formats is characterized by the implementation-defined value of FLT_EVAL_METHOD:19)

In 6.8.6.4 The return statement, add to footnote 136:

The representation of floating-point values may have wider range or precision and is determined by FLT_EVAL_METHOD. A cast may be used to remove this extra range and precision.

In 5.1.2.3 Program Execution, paragraph 12, change the second sentence to:

Implementation created intermediate values are independent of whether they are represented in a register or in memory.

In 6.7.1 Storage-class specifiers, add to paragraph 4:

A floating object with storage-class register may have greater range or precision than an auto object of the same type.


Comment from WG14 on 2003-03-06:

Committee Discussion

A floating object with storage-class register shall not have greater range or precision than an auto object of the same type. The reason for this is the assignment operator. The only way a register variable may be altered is via assignment; and assignment removes all extra range and precision.

Technical Corrigendum

In 5.2.4.2.2 Characteristics of floating types <float.h>, change paragraph 7 to:

Except for assignment and cast (which remove all extra range and precision), the values of operations with floating operands and values subject to the usual arithmetic conversions and of floating constants are evaluated to a format whose range and precision may be greater than required by the type. The use of evaluation formats is characterized by the implementation-defined value of FLT_EVAL_METHOD:19)

In 6.8.6.4 The return statement, add to footnote 136:

The representation of floating-point values may have wider range or precision and is determined by FLT_EVAL_METHOD. A cast may be used to remove this extra range and precision.



Issue 0291: corrections to requirements on inexact floating-point exceptions

Authors: WG 14, P.J. Plauger
Date: 2003-08-29
Reference document: ISO/IEC WG14 N1024
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_291.htm

Summary

IEC 60559 says very little about the setting of the inexact floating-point exception. C99 perhaps says a bit too much. Inexact is a condition that can arise when computing an expression as innocuous as 2.0/3.0, so it happens all the time during floating-point computations. It is thus arguably of little practical use. And it is rather difficult to avoid in writing math functions. Requiring math functions to set, or not set, inexact is thus arguably of more cost than benefit.

What follows is a review of certain statements in the C99 Standard, with suggestions for making them more sensible.

7.12.9.3 promises that nearbyint will not set inexact. This is a tiresome but not onerous requirement. It is also all that distinguishes nearbyint from rint, so the requirement should probably be retained.

7.12.9.4 says that rint:

may raise the inexact floating-point exception if the result differs in value from the argument.

This grants license to perform faster operations than are permitted nearbyint, but doesn't promise to reliably set inexact. Note that it is otherwise foolish for rint to set inexact, because the rounded result is always exactly the expected result. It is a false analogy to match the behavior of lrint or llrint, where the library functions are arguably mapping floating-point values to integer values, using a recipe for making the best of matters when the integer cannot exactly represent the original value.

Given the small distinction between rint and nearbyint, the latitude to set inexact should probably also be retained. (It is also worth an explicit mention, despite the general license suggested below for all math functions.)

Footnote 301 in F.4 says:

ANSI/IEEE 854, but not IEC 60559 (ANSI/IEEE 754), directly specifies that floating-to-integer conversions raise the inexact floating-point exception for non-integer in-range values. In those cases where it matters, library functions can be used to effect such conversions with or without raising the inexact floating-point exception. See rint, lrint, llrint, and nearbyint in <math.h>.

This clearly overstates the case, suggesting as it does that rint reliably sets inexact.

SUGGESTION: Remove rint from the list in the last sentence.

F.9, para 8 says:

Whether or when the trigonometric, hyperbolic, base-e exponential, base-e logarithmic, error, and log gamma functions raise the inexact floating-point exception is implementation-defined. For other functions, the inexact floating-point exception is raised whenever the rounded result is not identical to the mathematical result.

Given the difficulty of avoiding inexact exceptions, and their consequential uselessness in most cases, this license should be extended to all library functions.

SUGGESTION: Change the above to:

Whether or when library functions other than nearbyint raise the inexact floating-point exception is unspecified.

F.9, para 9 says:

Whether the inexact floating-point exception can be raised when the rounded result actually does equal the mathematical result is implementation-defined. Whether the underflow (and inexact) floating-point exception can be raised when a result is tiny but not inexact is implementation-defined.(312) Otherwise, as implied by F.7.6, the <math.h> functions do not raise spurious floating-point exceptions (detectable by the user).

The first sentence is mooted by the earlier suggested change. The second sentence (and the footnote, discussed below) doesn't go far enough. Avoiding intermediate underflows can be as annoying, and fruitless, as avoiding intermediate inexact reports. Library functions should report underflow if the final result underflows, but they should also have the latitude not to avoid reporting intermediate underflows.

SUGGESTION: Change the above to:

Whether or when library functions raise an undeserved underflow floating-point exception is unspecified.(312) Otherwise, as implied by F.7.6, the <math.h> functions do not raise spurious floating-point exceptions (detectable by the user).

Footnote 312 says:

It is intended that undeserved underflow and inexact floating-point exceptions are raised only if determining inexactness would be too costly.

SUGGESTION: Change the above to:

It is intended that undeserved underflow and inexact floating-point exceptions are raised only if avoiding them would be too costly.

F.9, para 10 says:

Whether the functions honor the rounding direction mode is implementation-defined.

This is inaccurate, since some functions (such as rint) are obliged to honor the rounding direction mode.

SUGGESTION: Change the above to:

Whether the functions honor the rounding direction mode is implementation-defined, unless explicitly specified otherwise.

F.9.6.4 says:

The rint functions differ from the nearbyint functions only in that they do raise the inexact floating-point exception if the result differs in value from the argument.

This contradicts 7.12.9.4, which does not require rint to set inexact.

SUGGESTION: Change the above to:

The rint functions differ from the nearbyint functions only in that they may raise the inexact floating-point exception if the result differs in value from the argument.

F9.8.3 says:

-nextafter(x, y) raises the overflow and inexact floating-point exceptions for x finite and the function value infinite. nextafter(x, y) raises the underflow and inexact floating-point exceptions for the function value subnormal or zero and x != y.

This is inconsistent with the general license for reporting overflow and underflow in J.3.1.2, which makes the setting of inexact with either of these exceptions implementation defined. It is also inconsistent with the general license for not reporting underflow on tiny results in J.3.6.

SUGGESTION: Change the above to:

-nextafter(x, y) raises the overflow floating-point exception for x finite and the function value infinite. nextafter(x, y) raises the underflow floating-point exception for the function value zero and x != y. nextafter(x, y) may raise the underflow floating-point exception for the function value subnormal and x != y.

J.3.1.2 includes as implementation-defined behavior:

Whether or when the trigonometric, hyperbolic, base-e exponential, base-e logarithmic, error, and log gamma functions raise the inexact floating-point exception in an IEC 60559 conformant implementation (F.9).

This should be unspecified behavior, not implementation defined.

SUGGESTION: Remove the above.


Comment from WG14 on 2004-09-28:

Committee Discussion

The intent of Annex F is to require the rint functions to raise inexact if the result differs from the argument value. This is in contrast to the weaker clause 7 statement that the rint functions may raise inexact. Moreover, nextafter has the behavior suggested by IEC 60559 and thus should not be changed. With these changes, the suggested changes are acceptable.

Technical Corrigendum

Change F.9, paragraph 8 from:

Whether or when the trigonometric, hyperbolic, base-e exponential, base-e logarithmic, error, and log gamma functions raise the "inexact" floating-point exception is implementation-defined. For other functions, the inexact floating-point exception is raised whenever the rounded result is not identical to the mathematical result.

to:

Whether or when library functions raise the inexact floating-point exception is unspecified, unless explicitly specified otherwise.

Change F.9, paragraph 9 from:

Whether the inexact floating-point exception can be raised when the rounded result actually does equal the mathematical result is implementation-defined. Whether the underflow (and inexact) floating-point exception can be raised when a result is tiny but not inexact is implementation-defined.(312) Otherwise, as implied by F.7.6, the <math.h> functions do not raise spurious floating-point exceptions (detectable by the user).

to:

Whether or when library functions raise an undeserved underflow floating-point exception is unspecified.(312) Otherwise, as implied by F.7.6, the <math.h> functions do not raise spurious floating-point exceptions (detectable by the user), other than the inexact floating-point exception.

Change Footnote 312 from:

It is intended that undeserved underflow and inexact floating-point exceptions are raised only if determining inexactness would be too costly.

to:

It is intended that undeserved underflow and inexact floating-point exceptions are raised only if avoiding them would be too costly.

Change F.9, paragraph 10 from:

Whether the functions honor the rounding direction mode is implementation-defined.

to:

Whether the functions honor the rounding direction mode is implementation-defined, unless explicitly specified otherwise.

Remove J.3.1.2 (from implementation-defined behavior):

Whether or when the trigonometric, hyperbolic, base-e exponential, base-e logarithmic, error, and log gamma functions raise the inexact floating-point exception in an IEC 60559 conformant implementation (F.9).



Issue 0292: Use of the word variable

Authors: Convener, J. Benito (convener)
Date: 2003-09-18
Reference document: ISO/IEC WG14 N1025
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_292.htm

Summary

Change the use of variable to object in those instances where the Standard is referring to an object.

Suggested Technical Corrigendum

EXAMPLE 2, 5.1.2.3, change

the value of each variable to size int

to

the value of each object to size int

Footnote 41, change

Thus, an automatic variable can be initialized to a trap representation without causing undefined behavior, but the value of the variable cannot be used until a proper value is stored in it.

to

Thus, an automatic object can be initialized to a trap representation without causing undefined behavior, but the value of the object cannot be used until a proper value is stored in it.

EXAMPLE 1, 6.5.16.1, change

Therefore, for full portability, the variable c should be declared as int.

to

Therefore, for full portability, the object c should be declared as int.

EXAMPLE, 6.7.5.1, change

EXAMPLE The following pair of declarations demonstrates the difference between a “variable pointer to a constant value” and a “constant pointer to a variable value”.

to

EXAMPLE The following pair of declarations demonstrates the difference between a “object pointer to a constant value” and a “constant pointer to a object value”.

6.8.5.3 #1, change

If clause-1 is a declaration, the scope of any variables it declares is the remainder of the declaration and the entire loop, including the other two expressions;

to

If clause-1 is a declaration, the scope of any objects it declares is the remainder of the declaration and the entire loop, including the other two expressions;

Footnote 134, change

Thus, clause-1 specifies initialization for the loop, possibly declaring one or more variables for use in the loop;

to

Thus, clause-1 specifies initialization for the loop, possibly declaring one or more objects for use in the loop;

Footnote 165, change

For a variable z of complex type, z == creal(z) + cimag(z)*I.

to

For the object z of complex type, z == creal(z) + cimag(z)*I.

Footnote 166, change

For a variable z of complex type, z == creal(z) + cimag(z)*I.

to

For the object z of complex type, z == creal(z) + cimag(z)*I.

7.6, #1, change

A floating-point status flag is a system variable whose value is set (but never cleared) when a floating-point exception is raised,

to

A floating-point status flag is a system object whose value is set (but never cleared) when a floating-point exception is raised,

7.6, #1, change

A floating-point control mode is a system variable whose value may be set by the user to affect the subsequent behavior of floating-point arithmetic.

to

A floating-point control mode is a system object whose value may be set by the user to affect the subsequent behavior of floating-point arithmetic.

F.8.1, change

The flags and modes in the floating-point environment may be regarded as global variables;

to

The flags and modes in the floating-point environment may be regarded as global objects;

Footnote 308, change

Use of float_t and double_t variables increases the likelihood of translation-time computation.

to

Use of float_t and double_t objects increases the likelihood of translation-time computation.

Annex I #2, bullet 11, change

or an enumeration variable that has the same type

to

or an enumeration object that has the same type


Comment from WG14 on 2006-04-04:

Committee Discussion

  1. No change needed.
  2. Sec 6.2.6.1 variable is common usage - no change needed.
  3. No change needed.
  4. No change needed.
  5. Change variable to identifiers.
  6. No change needed.
  7. No change needed.
  8. No change needed.
  9. No change needed.
  10. No change needed.
  11. No change needed.
  12. No change needed.
  13. No change needed.
  14. Agree with suggested change.

Technical Corrigendum

6.8.5.3 #1, change

If clause-1 is a declaration, the scope of any variables it declares is the remainder of the declaration and the entire loop, including the other two expressions;

to

If clause-1 is a declaration, the scope of any identifiers it declares is the remainder of the declaration and the entire loop, including the other two expressions;

Annex I #2, bullet 11, change

or an enumeration variable that has the same type

to

or an enumeration object that has the same type



Issue 0293: Typo in Standard - double complex instead of complex in an example

Authors: Tydeman (US)
Date: 2003-10-24
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_293.htm

Summary

6.7.8, paragraph 24, example 1.

complex c = 5 + 3 * I

should changed to

double complex c = 5 + 3 * I

Suggested Technical Corrigendum

Change complex to double complex in the example.


Comment from WG14 on 2004-03-01:

Technical Corrigendum

6.7.8, paragraph 24, example 1.

complex c = 5 + 3 * I

changed to

double complex c = 5 + 3 * I


Issue 0294: Technical question on C99 restrict keyword

Authors: INCITS, Greg Davis, Green Hills Software
Date: 2003-08-14
Status: Closed
Converted from: summary-c99.htm, dr_294.htm

Summary

I have a question on section 6.7.3.1 of the C99 spec.

Paragraph 4 is where this seems to get complicated.

Question 1)

"...Every other lvalue used to access the value of X shall also have its address based on P".

Consider the following example:

        #include <stdlib.h>
        char * restrict a, * restrict b;

        void copy(char * restrict dest, char * restrict source)
        {
         int i;
        for (i = 0; i < 10; i++)
            dest[i] = source[i];
        }

        int main()
        {
         a = calloc(10);
         b = calloc(10);
         copy(a, b);
         return 0;
        }

Is this a legal program? If so, could you explain the following? From the standpoint of main(), the memory in a is modified through the call to copy(). However, it seems to me that based on the definition of based on, the writes that modify *a are not based on the pointer a, but instead they're based on dest. Doesn't this violate the guarantee above?

Question 2)

"Every access that modifies X shall be considered also to modify P, for the purposes of this subclause." - Why is this necessary?

Question 3)

The same question for the rules on the copying of restrict pointers ("If P is assigned the value of a pointer expression E that is based on another restrict pointer object P2, associated with block B2, then either the execution of B2 shall begin before the execution of B, or the execution of B2 shall end prior to the assignment."). Why is this necessary?


Comment from WG14 on 2004-09-28:

Committee Response

Question 1)

Yes, the program conforms to all requirements in the specification for the restrict qualifier (though the call to function calloc should have two arguments).

Some interpretation of this question is provided to clarify the response. The response answers the interpretation.

The interpretation of this question is: I can see how the rules are followed for the restrict qualifier on dest, relative to the execution of function copy, but I don't see how the rules are followed for the restrict qualifier on a, relative to the execution of main.

Here is a spelling out of all the requirements in the specification of the restrict qualifier for this example. The following identify definitions in the specification of the restrict qualifier.

The requirements in the specification are then:

Contrary to what is implied in the question, an lvalue can have its address based on more than one restricted pointer, provided each is associated with a different (activation of a) block. In the example, the address of lvalue dest[i] in copy() is based not only on dest but also on a (because dest receives the value of a when the call is made).

[Note that there would be undefined behavior if there were also a reference to a[i] within the body of copy(), because the address of that lvalue would not be based on dest.]

Question 2)

This is necessary for the effectiveness of the restrict qualifier for multiple levels of indirection. Consider the example:

 void reverse(char * restrict * restrict dest,
               char * restrict * restrict source)
  {
   int i,j;
   for (i = 0; i < 10; i++)
     for (j = 0; j < 10; j++)
      dest[i][j] = source[i][9-j];
  }

Although the objects dest[i][j] are modified by the assignment statements, the pointer objects dest[i] are not. Without the clause quoted above, the top-level restrict qualifiers in the declarations of dest would have no effect, and a call of the form reverse(x,x) would have defined behavior if the elements of x point to 10 disjoint arrays of 10 chars. With the clause, the top-level qualifiers have the same effect as if those pointer objects were modified, so the iterated assignments are asserted to be fully free of aliasing for the modified objects, and a call of the form reverse(x,x) does have undefined behavior.

Question 3)

This is necessary to allow a translator to assume that two restricted pointers declared in the same scope cannot be used to alias the same object. Consider an extreme example for file scope pointers:

   char * restrict p;
    char * restrict q;

    void foo () { p = q; q = p; }

After the assignments in a call to foo(), each of the two pointers is based on the other. Without the rules quoted above, this would be allowed and would effectively enable aliasing despite the qualifiers. This possibility would, in turn, generally undermine the benefit of the restrict qualifier, because a translator would have to prove that there were no such assignments before taking advantage of restrict qualifiers.

[The assignments that are allowed are necessary to allow pointer values based on restricted pointers to be used in argument and return expressions.]



Issue 0295: Incomplete types for function parameters

Authors: Neil Booth, Project Editor (Larry Jones)
Date: 2004-03-19
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_295.htm

Summary

The standard appears to be contradictory with respect to whether a function parameter is permitted to have an incomplete type in a prototype other than the function definition.

6.7.5.3p12 says:

If the function declarator is not part of a definition of that function, parameters may have incomplete type....

But 6.7p7 says:

If an identifier for an object is declared with no linkage, the type for the object shall be complete by the end of its declarator...; in the case of function arguments [n.b., that should be parameters, not arguments] (including in prototypes), it is the adjusted type (see 6.7.5.3) that is required to be complete.

If the intent is to allow incomplete types, there do not appear to be any constraints forbidding constructions like:

void func(void parm);

Comment from WG14 on 2004-09-28:

Committee Discussion

The Committee agrees that “function arguments” should be “function parameters”. The cited text from 6.7p7 refers to the declarations of parameters in the definition of that function; each parameter declares an object whose adjusted type is required to be complete. Declarations of parameters in prototypes which are not part of the definition of that function are permitted to declare incomplete types. Whenever that function is called, arguments are implicitly converted to the types of the corresponding parameters; see 6.5.2.2p7. The requirements upon assignment require that the types of the corresponding parameters are complete types, at the point of calling the function. The constraint at 6.5.16p2 requires a modifiable lvalue for the left operand of assignment, and according to 6.3.2.1p1, a modifiable lvalue shall not have incomplete type.

The Committee agrees that there do not appear to be any constraints forbidding constructions like

void func(void parm);

nor are any semantics provided for this construction.

Technical Corrigendum

Change 6.7p7

in the case of function arguments (including in prototypes)

to:

in the case of function parameters (including in prototypes)



Issue 0296: Is exp(INFINITY) overflow? A range error? A divide-by-zero exception? INFINITY without any errors?

Authors: WG 14, Fred Tydeman (USA)
Date: 2004-02-10
Reference document: N1053
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_296.htm

Summary

I believe that there are some words missing from 7.12.1 Treatment of error conditions. Currently, the words allow exp(INFINITY) to be considered an overflow of the divide-by-zero type. This is wrong. An infinite result from infinite operands is not an error; it is an exact unexceptional operation.

Details from C99+TC1

Paragraph 4 in 7.12.1 Treatment of error conditions, currently has:

A floating result overflows if the magnitude of the mathematical result is finite but so large that the mathematical result cannot be represented without extraordinary roundoff error in an object of the specified type. If a floating result overflows and default rounding is in effect, or if the mathematical result is an exact infinity (for example log(0.0)), then the function returns the value of the macro HUGE_VAL, HUGE_VALF, or ...; if the integer expression math_errhandling & MATH_ERREXCEPT is nonzero, the "divide-by-zero" floating-point exception is raised if the mathematical result is an exact infinity ...

In addition, IEEE-754 has in 6.1 Infinity Arithmetic:

Arithmetic on INFINITY is always exact and therefor shall signal no exceptions, except for the invalid operations specified for INFINITY in 7.1.

The invalid operations on INFINITY in IEEE-754 are: INF-INF, 0*INF, INF/INF, INF REM y, sqrt(-INF).

Suggested Technical Corrigendum

Add ", from finite arguments," as indicated below to paragraph 4 in 7.12.1 Treatment of error conditions.

A floating result overflows if the magnitude of the mathematical result is finite but so large that the mathematical result cannot be represented without extraordinary roundoff error in an object of the specified type. If a floating result overflows and default rounding is in effect, or if the mathematical result is an exact infinity, from finite arguments, (for example log(0.0)), then the function returns the value of the macro HUGE_VAL, HUGE_VALF, or ...

In addition, add the following to the Rationale in 7.12.1:

Operations on INFINITY are either invalid or exact. Some examples of invalid operations are: INF-INF, INF*0, INF/INF, sqrt(-INF), cexp(r+I*INF). Some examples of exact operations, which also are unexceptional, are INF+x, INF*x, INF/x, sqrt(+INF), exp(INF).


Comment from WG14 on 2006-04-04:

Committee Discussion (for history only)

The following table tries to list all math functions that have an infinity for an input or an infinity for an output, as specified by Annex F.

Inf -> Inf

acosh(+INF)
asinh
cosh
sinh
exp(+INF)
exp2(+INF)
expm1(+INF)
frexp
ldexp
log(+INF)
log10(+INF)
log1p(+INF)
log2(+INF)
logb
modf
scalb
cbrt
fabs
hypot
pow(x,-INF), |x| < 1
pow(x,+INF), |x| > 1
pow(-INF,y), y > 0
pow(+INF,y), y > 0
sqrt(+INF)
lgamma
tgamma(+INF)
ceil
floor
nearbyint
rint
round
trunc
copysign(INF,y), y is anything
nextafter(INF,INF)
nexttoward(INF,INF)
fdim(INF,-INF)
fmax(+INF,any)
fmin(-INF,any)
fma(INF,INF,INF), x*y has same sign of z

Inf -> NaN + FE_INVALID

acos
asin
cos
sin
tan
acosh(-INF)
atanh
log(-INF)
log10(-INF)
log1p(-INF)
log2(-INF)
sqrt(-INF)
tgamma(-INF)
lrint
llrint
lround
llround
fmod(INF,any)
remainder(INF,any)
remquo(INF,any)
fma(INF,INF,INF), x*y has opposite sign of z
fma(0,INF,z), z not a NaN
fma(x,INF,-INF), x has same sign as INF

Inf -> finite

atan
atan2
tanh
exp(-INF)
exp2(-INF)
expm1(-INF)
pow(0,+INF)
pow(-1,INF)
pow(+1,INF)
pow(INF,0)
pow(x,-INF), |x| > 1
pow(x,+INF), |x| < 1
pow(-INF,y), y < 0
pow(+INF,y), y < 0
erf
erfc
fmod(x,INF), x not infinite
remainder(x,INF), x finite
remquo(x,INF), x finite
copysign(x,INF), x finite
fdim(INF,INF)
fmax(-INF,y), y finite
fmin(+INF,y), y finite

finite -> Inf + FE_DIVBYZERO

atanh(+/-1)
log(+/-0)
log10(+/-0)
log1p(-1)
log2(+/-0)
logb(+/-0)
pow(0,y), y an odd integer < 0
pow(0,y), y < 0 and not an odd integer [and finite]
lgamma(x), x is negative integer or zero
tgamma(+/-0)

All functions that have an exact infinity result and have an error, have finite arguments.

Technical Corrigendum

Add ", from finite arguments," as indicated below to paragraph 4 in 7.12.1 Treatment of error conditions.

A floating result overflows if the magnitude of the mathematical result is finite but so large that the mathematical result cannot be represented without extraordinary roundoff error in an object of the specified type. If a floating result overflows and default rounding is in effect, or if the mathematical result is an exact infinity, from finite arguments, (for example log(0.0)), then the function returns the value of the macro HUGE_VAL, HUGE_VALF, or ...

Rationale Change

Add the following to 7.12.1:

Operations on INFINITY are either invalid or exact. Some examples of invalid operations are: INF-INF, INF*0, INF/INF, sqrt(-INF), cexp(r+I*INF). Some examples of exact operations, which also are unexceptional, are INF+x, INF*x, INF/x, sqrt(+INF), exp(INF).



Issue 0297: May FE_* floating-point exception flags have bits in common?

Authors: WG 14, Fred Tydeman (USA)
Date: 2003-11-29
Reference document: N1045
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_297.htm

Summary

May the floating-point exception flags of 7.6 Floating-point environment <fenv.h>, paragraph 5, have bits in common, e.g., the AND between two of the FE_* macros be nonzero?

Details from C99+TC1

Suppose that the floating-point exception flags of 7.6 Floating-point environment <fenv.h> are defined as follows:

 #define FE_INVALID   0x8001
  #define FE_DIVBYZERO 0x8002
  #define FE_OVERFLOW  0x8004
  #define FE_UNDERFLOW 0x8008
  #define FE_INEXACT   0x8010

That is, there is a bit in common to at least two of the macros, in this case, it is common to all five macros. This is allowed by the current C99 wording. That bit here could mean: any floating-point exception is raised.

Clive Feather scanned through Annex B, and concluded that this is really the only case of flags being allowed to have common bits, which could be why we haven't spotted this condition before now.

Does this cause any problems?

Yes. Consider the example code in 7.6.2.5:

if (set_excepts & FE_INVALID) f();
  if (set_excepts & FE_OVERFLOW) g();

Suppose that just FE_DIVBYZERO is raised, e.g., set_excepts is 0x8002. Then, both of the above tests would report true (which is wrong), and both f() and g() would be called.

I know of two solutions:

  1. Require that there be no bits in common to any of these FE_* floating-point exception macros. One way is to change the last sentence of paragraph 5 of 7.6 to be:

    The defined macros expand to integer constant expressions with values such that bitwise ORs of all combinations of the macros result in distinct values, and furthermore, bitwise ANDs of all combinations of the macros result in zero.

    In addition, we could add a footnote to that sentance along the lines of:

    The macros should be distinct powers of two.

    Possible problem: This could break existing implementations. Anyone know of an implementation that would break?

    All feedback I have received says this is what we "designed" and is the only sane solution; it is also what people expect.

  2. Add another macro, such as FE_EXP_MASK, that is the OR of all these macros, but without any of the bits in common. In this case, it would be 0x001f. If we choose this solution, then we will need to redo the examples that test the floating-point exception flags. For example, in 7.6.2.5, the tests would become:

    if (set_excepts & FE_INVALID & FE_EXP_MASK) f();
      if (set_excepts & FE_OVERFLOW & FE_EXP_MASK) g();
    

    Possible problem: This would require existing user programs to be recoded.

    Many of us do not like this solution, and if it were allowed, would be very bad news.

Suggested Technical Corrigendum

Change the last sentence of paragraph 5 of 7.6 Floating-point environment <fenv.h> to be:

The defined macros expand to integer constant expressions with values such that bitwise ORs of all combinations of the macros result in distinct values, and furthermore, bitwise ANDs of all combinations of the macros result in zero.

In addition, add a footnote to that sentance along the lines of:

The macros should be distinct powers of two.


Comment from WG14 on 2004-09-28:

Technical Corrigendum

Change the last sentence of paragraph 5 of 7.6 Floating-point environment <fenv.h> to be:

The defined macros expand to integer constant expressions with values such that bitwise ORs of all combinations of the macros result in distinct values, and furthermore, bitwise ANDs of all combinations of the macros result in zero.

In addition, add a footnote to that sentance along the lines of:

The macros should be distinct powers of two.



Issue 0298: Validity of constant in unsigned long long range

Authors: Convener, J. Stephen Adamczyk
Date: 2004-03-31
Reference document: N1046
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_298.htm

Summary

Consider a constant 9223372036854775808 in a C99 implementation that has 64-bit two's complement long long, and no extended integer types.

6.4.4.1 says that an unsuffixed decimal constant has the first of the types on the following list into which its value will fit: int, long int, long long int. In this case, the value does not fit into any of those types, and there are no extended integer types to try. (The value would fit into unsigned long long, but that's not on the list.)

So I conclude that this constant is invalid, just as a grossly too-large constant (say, one consisting of a 1 followed by 1,000 zeroes) would be invalid. (And I think that's a good thing, because otherwise this constant could be unsigned on some implementations and signed on others that have larger extended integer types.)

However, I'm not sure 6.4.4.1 (or 6.4.4) says anything that requires an error, or even gives meaning to this constant. It doesn't say what happens if the constant doesn't fit in any type on its list and there are no extended integer types.

Is this a defect, or was this intentionally worded vaguely to allow latitude to implementations?

A related issue comes up with UINT64_C(9223372036854775808). One plausible implementation for the macro UINT64_C would seem to be to cast the constant to the proper type. However, that does not work in this particular case, because the constant before casting is the same invalid constant discussed above. Another plausible implementation (and suggested by 7.18.4.1p2) is to concatenate a suffix to the constant, e.g., a "U" in this case. Sounds good, but 7.18.4p2 doesn't say that the argument to the macro must be an unsuffixed constant; indeed it says that the syntax must match 6.4.4.1, which implies that a suffix is allowed.

So if 9223372036854775808 is an invalid constant, it seems that an implementation must rely on compiler magic to get UINT64_C right; the tricks available with standard macros don't work.

Suggested Technical Corrigendum


Comment from WG14 on 2007-09-06:

Committee Discussion

The Committee believes that the Constraint in 6.4.4 applies, and that a constant must have a type. If a type cannot be assigned, the program is invalid and violates the Constraint.

The second part involves uint64_c. The macros were not intended to be very smart. It is permissible for them to use compiler magic.

Technical Corrigendum

Change the constraint in 6.4.4 to read:

Each constant shall have a type and the value of a constant shall be in the range of representable values for its type.

Add the following sentence as last sentence of the paragraph after the list in 6.4.4.1:

If an integer constant cannot be represented by any type in its list and has no extended integer type, then the integer constant has no type.

7.18.4, paragraph 2 - change

"a decimal, octal, or hexadecimal constant"

to

"an unsuffixed integer constant".



Issue 0299: Is cabs() a type-generic macro?

Authors: WG 14, Fred Tydeman (USA)
Date: 2004-08-13
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_299.htm

Summary

The standard is not clear as to which type-generic macro(s) should be used to compute the absolute value of real, complex, and imaginary types.

Details

Here are two viewpoints.

1) cabs() is not a type-generic macro. Instead fabs() covers fabsf(), fabs(), fabsl(), cabsf(), cabs(), and cabsl().

If this viewpoint is correct, then 7.22p2 may need to be updated along the lines of "except modf and cabs". Also, in 7.22p7 (3rd line from end), cabs(fc) should be changed to fabs(fc).

2) cabs() is a type-generic macro (but only for complex arguments). That is cabs() covers cabsf(), cabs(), and cabsl(). In addition, fabs() covers fabsf(), fabs(), fabsl(), cabsf(), cabs(), and cabsl().

If this viewpoint is correct, then 7.22p6 needs to be updated with cabs. Also, B.21 needs to have cabs added to it.

It seems clear that cabs() is not a type-generic macro.

In addition, it is not clear what modf is in 7.22p5.

Suggested Technical Corrigendum

7.22p5 Add ", except modf" after "<math.h>"

7.22p7 (3rd line from end), cabs(fc) should be changed to fabs(fc).


Comment from WG14 on 2006-04-04:

Committee Discussion

7.22p2 says that every function in <math.h> and <complex.h> without an l or f suffix has a corresponding type-generic macro. Except modf.

However, 7.22p2 says nothing about what the macro is called.

7.22p4 says that if there is a function F() in <math.h> and a corresponding function cF() in <complex.h>, then the TG-macro for both F() and cF() is called "F". In addition, the TG-macro for both fabs() and cabs() is called "fabs".

7.22p5 and 7.22p6 say that for all remaining functions that have TG-macros, the macro has the same name as the function.

However, none of 7.22p4 to 7.22p6 say which functions have TG-macros.

Adding "except cabs" to 7.22p2 would directly contradict 7.22p4, because it says that there is no TG-macro corresponding to cabs (and, therefore, fabs).

If there's a defect in the wording, it's that 7.22p5 should say "except modf" after "<math.h>". Or all of 7.22p4 to 7.22p6 should have something like "Where a function has a corresponding type-generic macro" inserted in them. But we don't even believe that is necessary.

To get the absolute value of a float complex using a type-generic macro, use fabs. Therefore, 7.22p7 (3rd line from end) needs to change cabs(fc) to fabs(fc).

As G.7p1 correctly shows, to take the absolute value of an imaginary type, use fabs.

Technical Corrigendum

7.22p5 Add ", except modf" after "<math.h>"

7.22p7 (3rd line from end), cabs(fc) should be changed to fabs(fc).



Issue 0300: Translation-time expresssion evaluation

Authors: WG 14, Fred Tydeman (USA)
Date: 2004-08-26
Status: Closed
Converted from: summary-c99.htm, dr_300.htm

Summary

The standard does not require translation-time expression evaluation to produce "obvious" values. For example, there is no requirement that static const double d = 1.23/4.56 - 1.23/4.56; be zero.

Details

5.2.4.2.2p7 discusses FLT_EVAL_FORMAT, range and precision of floating-point constants and operations.

6.4.4.2p5 discusses translation time conversion of floating-point constants to internal format.

6.6p5 discusses translation time evaluation of floating-point constant expressions.

F.7.2p2 and footnote 306 discusses conversion of floating-point constants to internal representation.

F.7.5p3 discusses initialization and internal representation of floating-point constants.

Currently, if FLT_EVAL_METHOD is negative, there is no requirement that the first 1.23 and the second 1.23 convert to the same internal representation; one could have more precision than the other. While the same range and precision is a requirement when FLT_EVAL_METHOD is 0, 1, or 2, there is no requirement that those two identical constants convert to the same value.

Currently, if FLT_EVAL_METHOD is negative, there is no requirement that the first '/' produce a result with the same precision as the second '/' (for the same operands). This is a requirement when FLT_EVAL_METHOD is 0, 1, or 2.

Without these two requirements, the best one can do to try to get zero is: static const double d = (double)((double)1.23/(double)4.56) - (double)((double)1.23/(double)4.56); and even that could fail if the first 1.23 and the second 1.23 convert to different values.

For translation-time expression evaluation to produce the "obvious" value, two requirments must be met: the same decimal constants must result in the same value and internal representation, and operators must use the same precision.

Suggested Technical Corrigendum

6.4.4.2 Floating constants: Add to paragraph 5: All floating-constants of the same source form in the same translation unit shall convert to the same internal format with the same value. Footnote: 1.23, 1.230, 123e-2, 123e-02, 1.23L are all different source forms, so need not convert to the same internal format and value.

Add to 6.4.4.2p7, All floating-constants with the same mathematical value and type in the same translation unit should convert to the same internal format and value. Footnote: 1.23, 1.230, 123e-2 and 123e-02 have the same mathematical value, so should convert to the same internal format and value.

6.6: Constant expression: Add a 12th paragraph: All operators with the same type(s) of floating-point operand(s) in the same translation unit shall use the same precision.


Comment from WG14 on 2006-03-05:

Committee Discussion

The Committee consensus is this is not a defect, and that this DR imposes a new requirement on implementations.

Committee Response

This is not really a requirement, but an area to be investigated that could be addressed in a future revision of the C Standard.



Issue 0301: Meaning of FE_* macros in <fenv.h>

Authors: WG 14, Fred Tydeman (USA)
Date: 2004-08-27
Status: Closed
Converted from: summary-c99.htm, dr_301.htm

Summary

Exactly WHERE are the MEANINGS of any of the FE_* macros defined in cases where <fenv.h> applies to an environment that is not IEEE-754 (IEC 60559)?

Details

5.1.2.3p2 Program execution says:

Accessing a volatile object, modifying an object, modifying a file, or calling a function that does any of those operations are all side effects,11) which are changes in the state of the execution environment. Evaluation of an expression may produce side effects.

11) The IEC 60559 standard for binary floating-point arithmetic requires certain user-accessible status flags and control modes. Floating-point operations implicitly set the status flags; modes affect result values of floating-point operations. Implementations that support such floating-point state are required to regard changes to it as side effects see annex F for details. The floating-point environment library <fenv.h> provides a programming facility for indicating when these side effects matter, freeing the implementations in other cases.

The above footnote is the closest I can find to a requirement that there is any relationship between floating-point operations, status flags, and modes. But, it is a footnote, and only for IEC 60559.

5.2.4.2.2p6 Characteristics of floating types <float.h> has:

The rounding mode for floating-point addition is characterized by the implementation-defined value of FLT_ROUNDS:18)

 -1 indeterminable
  0 toward zero
  1 to nearest
  2 toward positive infinity
  3 toward negative infinity

All other values for FLT_ROUNDS characterize implementation-defined rounding behavior.

18) Evaluation of FLT_ROUNDS correctly reflects any execution-time change of rounding mode through the function fesetround in <fenv.h>.

The above mentions, but does not define, some rounding modes.

7.6p5 Floating-point environment <fenv.h> has:

Each of the macros

   FE_DIVBYZERO
   FE_INEXACT
   FE_INVALID
   FE_OVERFLOW
   FE_UNDERFLOW

is defined if and only if the implementation supports the floating-point exception by means of the functions in 7.6.2. 175) Additional implementation-defined floating-point exceptions, with macro definitions beginning with FE_ and an uppercase letter, may also be specified by the implementation.

175) The implementation supports an exception if there are circumstances where a call to at least one of the functions in 7.6.2, using the macro as the appropriate argument, will succeed. It is not necessary for all the functions to succeed all the time.

The above mentions, but does not define, some floating-point exceptions.

If an implementation defines a new floating-point exception, FE_BLUEMOON, such that:

but FE_BLUEMOON is NOT tied to any floating-point operation, is this valid "support"?

7.6p7 Floating-point environment <fenv.h> has:

Each of the macros

   FE_DOWNWARD
   FE_TONEAREST
   FE_TOWARDZERO
   FE_UPWARD

is defined if and only if the implementation supports getting and setting the represented rounding direction by means of the fegetround and fesetround functions. Additional implementation-defined rounding directions, with macro definitions beginning with FE_ and an uppercase letter, may also be specified by the implementation. The defined macros expand to integer constant expressions whose values are distinct nonnegative values.176)

176) Even though the rounding direction macros may expand to constants corresponding to the values of FLT_ROUNDS, they are not required to do so.

The above mentions, but does not define, some rounding modes.

F.8.1p1 Global transformations says:

Floating-point arithmetic operations and external function calls may entail side effects which optimization shall honor, at least where the state of the FENV_ACCESS pragma is "on". The flags and modes in the floating-point environment may be regarded as global variables; floating-point operations (+, *, etc.) implicitly read the modes and write the flags.

The above is a clear description of how modes and flags interact with operations, but it applies only to IEEE-754.

Suggested Technical Corrigendum

7.6 Floating-point environment <fenv.h>: Add to paragraph 5:

A necessary condition for an implementation to support a given FE_* exception is that it implicitly occur as a side effect of at least one floating-point operation. Just having feraiseexcept(), fetestexcept() and feclearexcept() succeed for a given FE_* exception is not sufficient.

FE_INVALID should be a side-effect of:

FE_DIVBYZERO should be a side-effect of dividing a non-zero finite number by zero, e.g., 1.0/0.0. There should be no exception when dividing an infinity by zero, nor when dividing a NaN by zero.

It is implementation defined as to whether FE_INVALID, FE_DIVBYZERO, or no exception is raised for zero / zero.

FE_OVERFLOW should be a side-effect of producing a rounded floating-point result (assuming an unbounded exponent range) larger in magnitude than the largest finite number.

FE_UNDERFLOW should be a side-effect of producing a rounded floating-point result (assuming an unbounded exponent range) smaller in magnitude than the smallest non-zero finite number, or an inexact denormal number smaller than the smallest non-zero normalized number.

FE_INEXACT should be a side-effect of producing a rounded floating-point result that differs from the mathematical (or infinitely precise) result.

Also in 7.6, change footnote 175 from "The implementation supports an exception if ..." to "The implementation supports an exception if that exception happens as a side-effect of at least one floating-point operation and if ..."

5.2.4.2.2 Characteristics of floating types <float.h>: Add to paragraph 6:

See 7.6 Floating-point environment paragraph 7 for meaning of these rounding modes.

7.6 Floating-point environment <fenv.h>: Add to paragraph 7:

A necessary condition for an implementation to support these rounding control modes is that they can be set explicitly and that they affect result values of floating-point operations. Just having fegetround() and fesetround() succeed for a given FE_* rounding direction is not sufficient.

FE_TOWARDZERO means the result shall be the format's value closest to and no greater in magnitude than the infinitely precise result. For example, if rounding to integer value in floating-point format, +3.7 rounds to +3.0 and -3.7 rounds to -3.0.

FE_UPWARD means the result shall be the format's value closest to and no less than the infinitely precise result. For example, if rounding to integer value in floating-point format, +3.1 rounds to +4.0 and -3.7 rounds to -3.0.

FE_DOWNWARD means the result shall be the format's value closest to and no greater than the infinitely precise result. For example, if rounding to integer value in floating-point format, +3.7 rounds to +3.0 and -3.1 rounds to -4.0.

FE_TONEAREST means the result shall be the format's value closest to the infinitely precise result. It is implementation defined as to what happens when the two nearest representable values are equally near. For example, if rounding to integer value in floating-point format, +3.1 rounds to +3.0 and +3.7 rounds to +4.0, and +3.5 rounds to either +3.0 or +4.0.

Add to J.3.6 Floating point:

-- to nearest rounding result when the two nearest representable values are equally near.

-- whether FE_INVALID, FE_DIVBYZERO, or no exception is raised for zero / zero.

Add 7.6 to the index entry for floating-point rounding mode.


Comment from WG14 on 2006-03-05:

Committee Discussion

Footnote 173 in 7.6 paragraph 1 also describes intent of <fenv.h>. Footnote 180 in 7.6.2.3 paragraph 2 mentions exceptions as raised by floating-point operations.

Some members would like FE_BLUEMOON to be a valid macro (even though none of the basic floating-point operations would raise it). Hence, they do not want to require the FE_* macros to be side-effects of floating-point operations.

The current FE_* macros are unspecified as that was the best compromise that could be agreed to by the various committee members when C99 was being developed.

Not really a defect, but a deficiency.

Two Heads of Delegations would like LIA-1 added as a normative reference by C99 as a way to define floating-point in C.

Several members believe that nailing down floating-point would be a good thing, but that the DR process is not the way to do it. Perhaps an amendment (similar to how wide characters were added to C90) should be done to C99 as a way to "clean up" floating-point. Several members would like 2.0+3.0 being 5.0 to be true.

Most of the proposed TC material should be added to the C Rationale.

This material could be added to C99 as Recommended Practice.

Committee Response

This is not really a defect, but an area which could be addressed in a future revision of the C Standard.



Issue 0302: 6.10.2p5: Adding underscore to portable include file name character set

Authors: WG21, Clark Nelson
Date: 2004-10-26
Reference document: ISO/IEC WG14 N1068
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_302.htm

Summary

In analyzing the differences in this paragraph between C99 and C++, I discovered that C89 admitted only letters in include file names with guaranteed unique mappings. C99 later added digits, while C++ independently added underscores. I personally don't recall any discussion or rationale behind either decision. It's clear that simply synchronizing C++ to C99 would be a technical change, and could (from a pedantic perspective) invalidate some existing code. The only way to synchronize the two standards without invalidating any existing code would be to allow underscores and digits in both standards. This may be considered a good thing in any event.

Note that in my proposed change the terms of reference have changed slightly. That's because, in the C++ standard, for good or ill, the terms letter and digit aren't defined in the (earlier) section describing the character set, as they are in C99 (whereas in C89, the terms appeared there without being definitions). In C++, letter is defined in the (later) library section, and digit is defined only as a non-terminal. It would of course be possible to rearrange things in the C++ standard to more closely match the C standard, but synchronizing things in this way would be much easier. And again, using the non-terminal symbols in this context may be considered an improvement in itself.

Suggested Technical Corrigendum

Change 6.10.2p5:

The implementation shall provide unique mappings for sequences consisting of one or more letters or digits (as defined in 5.2.1) nondigits or digits (6.4.2.1) followed by a period (.) and a single letter nondigit. The first character shall be a letter not be a digit. The implementation may ignore the distinctions of alphabetical case and restrict the mapping to eight significant characters before the period.


Comment from WG14 on 2006-03-05:

Technical Corrigendum

Change 6.10.2p5:

The implementation shall provide unique mappings for sequences consisting of one or more letters or digits (as defined in 5.2.1) nondigits or digits (6.4.2.1) followed by a period (.) and a single letter nondigit. The first character shall be a letter not be a digit. The implementation may ignore the distinctions of alphabetical case and restrict the mapping to eight significant characters before the period.



Issue 0303: 6.10p2: Breaking up the very long sentence describing preprocessing directive

Authors: WG21, WG21
Date: 2004-10-26
Reference document: ISO/IEC WG14 N1068
Status: Fixed
Fixed in: C99 TC3
Cross-references: 0250
Converted from: summary-c99.htm, dr_303.htm

Summary

The sentence describing a preprocessing directive is fearsomely long.

Suggested Technical Corrigendum

Change 6.10p2:

A preprocessing directive consists of a sequence of preprocessing tokens that begins with . The first token in the sequence is a # preprocessing token that (at the start of translation phase 4) is either the first character in the source file (optionally after white space containing no new-line characters) or that follows white space containing at least one new-line character, and is ended by the next . The last token in the sequence is the first new-line character that follows the first token in the sequence.140) A new-line character ends the preprocessing directive even if it occurs within what would otherwise be an invocation of a function-like macro.


Comment from WG14 on 2006-03-05:

Committee Response

TC2 (and specifically DR 250) changed that sentence into a definition.

Technical Corrigendum

Change 6.10p2:

A preprocessing directive consists of a sequence of preprocessing tokens that begins with that satisfies the following constraints. The first token in the sequence is a # preprocessing token that (at the start of translation phase 4) is either the first character in the source file (optionally after white space containing no new-line characters) or that follows white space containing at least one new-line character, and is ended by the next . The last token in the sequence is the first new-line character that follows the first token in the sequence.140) A new-line character ends the preprocessing directive even if it occurs within what would otherwise be an invocation of a function-like macro.



Issue 0304: Clarifying illegal tokens in #if directives

Authors: WG21, WG21
Date: 2004-10-26
Reference document: ISO/IEC WG14 N1068
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_304.htm

Summary

According to 6.10.1p3, "each preprocessing token [in a #if directive] is converted into a token." But what if, for example, the line contains an unmatched quote mark, or a preprocessing number like 4hello? How is such a preprocessing token converted into a token? No indication is given that the conversion may fail.

Suggested Technical Corrigendum

Insert new constraint paragraph after 6.10.1p1:

Each preprocessing token that remains after all macro replacements have occurred shall be in the lexical form of a token (6.4).


Comment from WG14 on 2006-04-04:

Technical Corrigendum

Insert new constraint paragraph after 6.10.1p1:

Each preprocessing token that remains after all macro replacements have occurred shall be in the lexical form of a token (6.4).



Issue 0305: 6.10.1p3: Clarifying handling of keywords in #if directives

Authors: WG21, WG21
Date: 2004-10-26
Reference document: ISO/IEC WG14 N1068
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_305.htm

Summary

This just clarifies that keywords are not treated specially in #if directives. (In C++, the keywords true and false are treated specially in this regard; I suspect that someone didn't want the sentence to read, "... all remaining identifiers, except for true and false, are replaced ...", for reasons which seem fairly obvious to me.)

Suggested Technical Corrigendum

Change the following sentence in 6.10.1p3:

After all replacements due to macro expansion and the defined unary operator have been performed, all remaining identifiers and keywords are replaced with the pp-number 0, and then each preprocessing token is converted into a token.


Comment from WG14 on 2006-03-05:

Committee Response

It is clear from the standard (in particular, the phases of translation) that there are not yet any keywords at the point in question.

Technical Corrigendum

Change the following sentence in 6.10.1p3:

After all replacements due to macro expansion and the defined unary operator have been performed, all remaining identifiers (including those lexically identical to keywords) are replaced with the pp-number 0, and then each preprocessing token is converted into a token.



Issue 0306: 6.10.3p9: Clarifying that rescanning applies to object-like macros

Authors: WG21, WG21
Date: 2004-10-26
Reference document: ISO/IEC WG14 N1068
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_306.htm

Summary

I suspect that this was introduced as a result of a public comment from someone who was confused (honestly or perversely) about 6.10.3.4p1: "After all parameters in the replacement list have been substituted, the resulting preprocessing token sequence is rescanned ..." (emphasis added). This clearly describes the rescanning of function-like macros, but because of the reference to parameters, may be taken as not applying to object-like macros.

Suggested Technical Corrigendum

Add a new sentence to the end of 6.10.3p9:

A preprocessing directive of the form

# define identifier replacement-list new-line

defines an object-like macro that causes each subsequent instance of the macro name145) to be replaced by the replacement list of preprocessing tokens that constitute the remainder of the directive. The replacement list is then rescanned for more macro names as specified below.


Comment from WG14 on 2006-03-05:

Technical Corrigendum

Add a new sentence to the end of 6.10.3p9:

A preprocessing directive of the form

# define identifier replacement-list new-line

defines an object-like macro that causes each subsequent instance of the macro name145) to be replaced by the replacement list of preprocessing tokens that constitute the remainder of the directive. The replacement list is then rescanned for more macro names as specified below.



Issue 0307: 6.10.3p10: Clarifiying arguments vs. parameters

Authors: WG21, WG21
Date: 2004-10-26
Reference document: ISO/IEC WG14 N1068
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_307.htm

Summary

Obviously, what appear in the definition syntax of a function-like macro are not its arguments, but its parameters. On the other hand, what is similar syntactically to a function call is obviously the invocation of the macro, not its definition. Clearly, there is confusion about whether this sentence is talking about the definition or an invocation.

Perhaps it would be clearer yet to say something like, "a function-like macro which takes arguments, similarly syntactically to a function call".

Suggested Technical Corrigendum

Change 6.10.3p10:

A preprocessing directive of the form

# define identifier lparen identifier-listopt ) replacement-list new-line
# define identifier lparen ... ) replacement-list new-line
# define identifier lparen identifier-list , ... ) replacement-list new-line

defines a function-like macro with arguments parameters, similar syntactically to a function call.


Comment from WG14 on 2006-03-05:

Technical Corrigendum

Change 6.10.3p10:

A preprocessing directive of the form

# define identifier lparen identifier-listopt ) replacement-list new-line
# define identifier lparen ... ) replacement-list new-line
# define identifier lparen identifier-list , ... ) replacement-list new-line

defines a function-like macro with arguments parameters, whose use is similar syntactically to a function call.



Issue 0308: Clarify that source files et al. need not be "files"

Authors: WG21, WG21
Date: 2004-10-26
Reference document: ISO/IEC WG14 N1068
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_308.htm

Summary

I do not recall the specific motivation for adding this note, but it's certainly true, and it seems harmless.

It should be noted that in the C++ standard, this text is an embedded non-normative note at the end of the description of phase 7 (parsing and semantic analysis). But the C standard does not have embedded notes, and the note is not actually specific to phase 7 (which talks principally about tokens, without even mentioning files). Adding the text to this footnote, which already points out an implication of the as-if rule for the phases of translation, would seem to be the ideal solution.

Suggested Technical Corrigendum

Change footnote 5 (5.1.1.2p1):

Implementations shall behave as if these separate phases occur, even though many are typically folded together in practice. Source files, translation units and translated translation units need not necessarily be stored as files, nor need there be any one-to-one correspondence between these entities and any external representation. The description is conceptual only, and does not specify any particular implementation.


Comment from WG14 on 2006-03-05:

Technical Corrigendum

Change footnote 5 (5.1.1.2p1):

Implementations shall behave as if these separate phases occur, even though many are typically folded together in practice. Source files, translation units and translated translation units need not necessarily be stored as files, nor need there be any one-to-one correspondence between these entities and any external representation. The description is conceptual only, and does not specify any particular implementation.



Issue 0309: Clarifying trigraph substitution

Authors: WG21, WG21
Date: 2004-10-26
Reference document: ISO/IEC WG14 N1068
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_309.htm

Summary

Obviously, "before any other processing" is already implied by the phases of translation, but it doesn't hurt to point out the implication here. And in general, a distributive description ("each" with singular) tends to be less ambiguous than a collective one ("all" with plural). The motivation for deleting the phrase "in a source file" is, as far as I can see, weak at best.

Suggested Technical Corrigendum

Change 5.2.1.1p1:

All occurrences in a source file Before any other processing takes place, each occurrence of one of the following sequences of three characters (called trigraph sequences12)) are is replaced with the corresponding single character.


Comment from WG14 on 2006-03-05:

Technical Corrigendum

Change 5.2.1.1p1:

All occurrences in a source file Before any other processing takes place, each occurrence of one of the following sequences of three characters (called trigraph sequences12)) are is replaced with the corresponding single character.



Issue 0310: Add non-corner case example of trigraphs

Authors: WG21, WG21
Date: 2004-10-26
Reference document: ISO/IEC WG14 N1068
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_310.htm

Summary

The existing corner case example is a good one. For some reason it was removed from C++, and I will propose that it be restored. But in general there are very few cases where the only example presented is a corner case. If trigraphs make any sense at all, then perhaps it would make sense to present a more realistic example (possibly even more realistic than this example).

Suggested Technical Corrigendum

Add new example paragraph before 5.2.1.1p2:

EXAMPLE 1:

??=define arraycheck(a,b) a??(b??) ??!??! b??(a??)

becomes

#define arraycheck(a,b) a[b] || b[a]

Comment from WG14 on 2006-03-05:

Technical Corrigendum

Add new example paragraph before 5.2.1.1p2:

EXAMPLE 1:

??=define arraycheck(a,b) a??(b??) ??!??! b??(a??)

becomes

#define arraycheck(a,b) a[b] || b[a]


Issue 0311: Definition of variably modified types

Authors: Joseph Myers <joseph@codesourcery.com>, UK C Panel
Date: 2005-03-04
Reference document: ISO/IEC WG14 N1099
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_311.htm

Summary

Variably modified types are defined by 6.7.5#3:

[#3] A full declarator is a declarator that is not part of another declarator. The end of a full declarator is a sequence point. If the nested sequence of declarators in a full declarator contains a variable length array type, the type specified by the full declarator is said to be variably modified.

It is desirable for the definition to look at the declarator rather than just the resulting type, so that function parameters adjusted from array to pointer type are variably modified if the array size is variable: in

    void
    f (int i, int a[static ++i])
    {
      // ...
    }

the increment of i must be evaluated for the definition of static in this context to make sense. However, what it means for the declarators to "contain" a type is unclear. The natural interpretation is that they include an array declarator with array size [*] or an expression which is not an integer constant expression. However, this does not cover cases such as

    int x;
    // ...
    typedef int vla[x];
    vla y[3];

where a typedef for a variably modified type is used. y is a VLA, and clearly ought to be variably modified, but nothing about the declarators makes it variably modified; only the declaration specifier does so.

Suggested Technical Corrigendum


Comment from WG14 on 2007-09-06:

Committee Discussion (for history only)

Declarators don't contain a type, it is the sequence of declarators that contains types.

The sentence in 6.7.5;p3 that defines variably modified types may be wrong, and that may not even be the right place for it to be defined. The definition ties it too closely to the declarator. In the example provided in the DR, the type of y is variably modified. The declarator for y does not include a variable length array type. Para 3 needs to have it's wording adjusted in some fashion, the text there is insufficient to provide us the answer.

The definition in the standard for variable length array does not seem to be in italics.

2006-Mar-29:

For the reason noted in the Summary, variably modified types do need to be tied to the declarator syntax.  But the current definition fails to state that a new type derived from a variably modified type is itself variably modified.

Committee Response

Yes, this is a defect in the definition..  The definition will be modified to state explicitly that types derived from a variably modified type are themselves variably modified.

Technical Corrigendum

[Note, these are relative to wg14's N1124.]

Change 3rd sentence in 6.7.5p3 from:

If the nested sequence of declarators in a full declarator contains a variable length array type, the type specified by the full declarator is said to be variably modified.

to

If in the nested sequence of declarators in a full declarator there is a declarator specifying a variable length array type, the type specified by the full declarator is said to be variably modified.  Furthermore, any type derived by declarator type derivation from a variably modified type is itself variably modified.



Issue 0312: Meaning of "known constant size"

Authors: Joseph Myers <joseph@codesourcery.com>, UK C Panel
Date: 2005-03-04
Reference document: ISO/IEC WG14 N1100
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_312.htm

Summary

Does "known constant size" mean something different from "not a VLA"? The phrase is used in the definition of composite types, 6.2.7#3:

-- If one type is an array of known constant size, the composite type is an array of that size; otherwise, if one type is a variable length array, the composite type is that type.

and in an example in 6.5.6#11 (where it doesn't cause problems), and in 6.7.5.2#4 to define VLAs:

[#4] If the size is not present, the array type is an incomplete type. If the size is * instead of being an expression, the array type is a variable length array type of unspecified size, which can only be used in declarations with function prototype scope;122) such arrays are nonetheless complete types. If the size is an integer constant expression and the element type has a known constant size, the array type is not a variable length array type; otherwise, the array type is a variable length array type.

Suppose the implementation does not accept any non-standard forms of constant expressions under 6.6#10, so that (int)+1.0 is an arithmetic constant expression but not an integer constant expression. Thus int[(int)+1.0] is a VLA type. But is int[1][(int)+1.0] a VLA type? The element type is a VLA type, but the element size is a known constant. If "known constant size" is interpreted to include some VLA cases, this also means further indeterminacy of composite types in such cases; is "an array of that size" a VLA of that size, or a non-VLA of that size, and may cases involving compatible array types with different known constant sizes (which would yield undefined behavior if executed) be rejected at translation time?

Suggested Technical Corrigendum


Comment from WG14 on 2006-04-04:

Committee Discussion (for history only)

The statement, "Suppose the implementation does not accept any non-standard forms of constant expressions under 6.6#10, so that (int)+1.0 is an arithmetic constant expression but not an integer constant expression." , implies an interpretation of the standard that the implementation can extend the meaning of what constitutes an integer constant expression. For example, that (int)+1.0 is an integer constant expression.

The committee does not believe that it does. Even if an implementation accepts other forms of constant expressions, paragraph 6.6#10 does not change the definition of an integer constant expression given by paragraph 6.6#6, and int[(int)+1.0] is still a VLA.

Paragraph 6.6#10 cannot be used to get around issuing diagnostics for constraint violations where integer constant expressions are required. Which we believe is what the first paragraph of the introductory text is implying

Technical Corrigendum

Add to 6.2.5, after Paragraph 22

A type has known constant size if the type is not incomplete and is not a variable length array type.



Issue 0313: Incomplete arrays of VLAs

Authors: Joseph Myers <joseph@codesourcery.com>, UK C Panel
Date: 2005-03-04
Reference document: ISO/IEC WG14 N1101
Status: Closed
Converted from: summary-c99.htm, dr_313.htm

Summary

If an incomplete array type has elements of unknown size, should the incomplete array type be a VLA type? The definition of VLA types in 6.7.5.2#4 only seems to make complete types into VLA types. In particular, does the following, at block scope, violate any constraint?

    int i;
    // ...
    int c[][i] = { 0 };

If it is not a VLA - and nothing in the standard seems to make it a VLA - then the initializer would seem to be valid, and to determine the size of the array. This seems rather against the spirit of prohibiting initializing VLAs in 6.5.2.5#1 (compound literals) and 6.7.8#3 (initializers).

Those appear to be the only places where it particularly matters whether such types are VLA types. In other cases, use of such types does not depend on whether they are VLA types, or yields a constraint violation whether or not they are VLA types, or in the case of

    static int c[][i];

at block scope violates the requirement of 6.7#7 for the type to be complete, so causing undefined behavior, though if the type were a VLA type then there would be a violation of the constraint in 6.7.5.2#2, so requiring a diagnostic.

Defining such types to be VLA types would ensure constraint violations in 6.5.2.5#1 and 6.7.5.2#2. 6.7.8#3 would need rewording to avoid "that is not a variable length array type" applying to "object type" only.

Suggested Technical Corrigendum


Comment from WG14 on 2006-03-05:

Committee Response

Per 6.7.8, paragraph 17, The initializer initializes the sub object of the array c[ ], which in this case is a VLA, therefore it violates the constraint in 6.7.8, paragraph 3.



Issue 0314: Cross-translation-unit tagged type compatibility

Authors: Joseph Myers <joseph@codesourcery.com>, UK C Panel
Date: 2005-03-04
Reference document: ISO/IEC WG14 N1102
Status: Closed
Converted from: summary-c99.htm, dr_314.htm

Summary

Compatibility of tagged types can be intransitive when there are multiple translation units:

// TU 1:
struct s;
struct t { struct s *a; };

// TU 2:
struct s { int p; };
struct t { struct s *a; };

// TU 3:
struct s { long q; };
struct t { struct s *a; };

where struct t in TU 1 is compatible with that in TU 2 and TU 3 but they are not compatible with each other.

C++ avoids problems with such cases by giving types linkage, meaning that the incompatible definitions of named struct types yield undefined behavior. In C types do not have linkage, and such incompatibilities can give rise to several problems. The requirement of 6.2.7#2 that "All declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined." does not seem sufficient to avoid all such problems.

Question 1: Does 6.2.7#2 refer to the types immediately after the declarations, or the types at any point where the declarations are in scope?

Question 2: If each of the above three translation units started extern struct t *x;, would there be undefined behavior?

Even if the requirement applies to the types anywhere in scope, this may not be enough. Each translation unit above could have prepended to it

struct t;
static void f(void) { extern struct t *x; }

and the incompatible completions are not within the scope of x. (x might then be defined in another translation unit that just says struct t *x;.)

The above example at least leads to incompatible "ultimate" types for x that the object has at the end of each translation unit, albeit outside the scope of the declaration. But now consider the following three translation units.

// TU 1:
struct s;
struct t { struct s *a; };
int g1(struct s *);
int g2(struct s *);
int f(struct t *p, int x) { return x ? g1(p->a) : g2(p->a); }

// TU 2:
struct t { int b; };
struct s { int a; struct t *z; };
int g1(struct s *p) { return p->a  + p->z->b; }

// TU 3:
struct t { long c; };
struct s { struct t *z; long a; };
int g2(struct s *p) { return p->a + p->z->c; }

Each object and function has a well-defined complete type. But a struct t in TU 1 may contain pointers to two different versions of struct s, and each of these contains pointers to an entirely different struct t from that in TU 1. This requires very strange gymnastics for an implementation inlining across translation units to inline g1 and g2 into f. There is no single translation unit representing a natural merger of the three above; renaming static objects with conflicting names does not suffice (indeed, there are no such objects), and renaming type names used in different names in different translation units does not help either because there is no single natural expression of a recursive completion of TU 1's struct t.

Question 3: Is an implementation required to accept compiling the three translation units above together into a program?

This issue arises directly from actual implementation problems implementing optimizations across multiple translation units in GCC. It is natural for an implementation to take multiple translation units and convert them into a language-independent intermediate representation of the whole program which is then optimized, and in so doing to unify the declarations in different translation units which refer to the same object or function. But unifying them involves unifying their types, and so recursively the types involved in the definitions of those types, and the above translation units, although apparently valid to link into a single program at present, do not admit of such a unification.

Suggested Technical Corrigendum


Comment from WG14 on 2008-09-12:

Committee Discussion (for history only)

2006-10-25, There was not consensus for the Proposed Committee Response listed below. There was no consensus that question 2 is undefined behavior. There does not seem to be specific words in the Standard that make it undefined behavior, however that may be what the Committee intended.

Spring 2007

See N1237.

Fall 2007

The Standard doesn't seem to specifically allow the compilation/linking of the three translations units in question, but is does not seem to disallow it either.

Spring 2008

Current response is good. However, is this is an issue that should be addressed in C1x? Looked again at N1237 (reviewed in Kona).

There is consensus that it should be possible for an implementation to combine the translation units of a program into a single internal representation and optimize that, unifying structure and union types across translation units where required to be compatible in the process.

Normally, it is possible to create a single translation unit equivalent to multiple translation units, after renaming static variables and functions and structure and union tags. DR314 question 3 is an example where such renaming is not possible. My proposal is to add a requirement that it is possible.

It was noted that this has been hanging around for several years. Needs someone to actually come up with the right words.

Proposed Committee Response

Question 1: Does 6.2.7#2 refer to the types immediately after the declarations, or the types at any point where the declarations are in scope?

Subclause 6.2.7 Paragraph 2 makes a statement about all declarations of the same object or function, regardless of where the declarations that object or function are. It requires that all declarations of the same object or function, even if those declarations are in different translation units of the program, to have compatible type.
Note also that if an object with struct or union type is declared with an incomplete type, and that type is later completed in the same scope, the type of the declaration is the completed type (Subclause 6.2.5, Paragraph 22). Under such conditions, the type of the object or function is the completed type, and that type must be compatible with any other declarations.

Question 2: If each of the above three translation units started extern struct t *x;, would there be undefined behavior?

Yes, undefined behavior.

Question 3: Is an implementation required to accept compiling the three translation units above together into a program?

It was never the Committees intention that the standard be interpreted this way.
This will be addressed in a future revision of the standard. See WG14 Nxxx.



Issue 0315: Implementation-defined bit-field types

Authors: Joseph Myers <joseph@codesourcery.com>, UK C Panel
Date: 2005-03-04
Reference document: ISO/IEC WG14 N1103
Status: Fixed
Fixed in: C11
Cross-references: 0335, 1007
Converted from: summary-c99.htm, dr_315.htm

Summary

C99 6.7.2#2 lists the valid combinations of type specifiers. 6.7.2#5 says:

[#5] Each of the comma-separated sets designates the same type, except that for bit-fields, it is implementation-defined whether the specifier int designates the same type as signed int or the same type as unsigned int.

6.7.2.1#4 says:

[#4] A bit-field shall have a type that is a qualified or unqualified version of _Bool, signed int, unsigned int, or some other implementation-defined type.

Some problems arise with use of an "other implementation-defined type", a new addition in C99.

1. Suppose an implementation supports bit-fields of types char, short, long and long long. Bit-fields of type int may be unsigned on that implementation. Must bit-fields of type char nevertheless have the same signedness as ordinary objects of type char, and similarly for those of types short (or short int), long (or long int), long long (or long long int)? The practice in C++ is that all these are implementation-defined (except that C++ does not include long long); it seems an oversight in the addition of implementation-defined bit-field types in C99 not to make such provision for char, short, long and long long bit-fields as is made for int bit-fields. (It might still be appropriate to ensure, for example, that short and short int have the same signedness as bit-field types, although that might be unsigned and so differ from the signedness of signed short and signed short int.) Footnote 104, reiterating that int as a bit-field type may be signed or unsigned, would also need amendment.

2. Suppose an implementation has 32-bit int (with no padding bits) and permits unsigned long long as an implementation-defined bit-field type. Consider the code:

  struct s { unsigned long long a : 37, b : 37; } x;
  // ...
  sizeof(x.a + x.b);

x.a and x.b have 37-bit unsigned integer types, by 6.7.2.1#9. Such types have an integer conversion rank greater than that of int, so are unchanged by the integer promotions. (That all the bit-field types have integer conversion ranks, and may need to be documented by implementations as extended integer types, is a consequence of the standard that may not be intended and may be surprising to some, but it is a logical consequence of the text of the standard.) Whether or not x.a and x.b have the same 37-bit type, (x.a + x.b) also has a 37-bit unsigned integer type. However, (x.a + x.b) does not designate a bit-field member, so it does not violate the constraints on sizeof. But what should sizeof(x.a + x.b) evaluate to, when (x.a + x.b) has such a bit-field type which does not occupy an integer number of bytes? Must an implementation define representations occupying an integer number of bytes (with some padding bits) for all such types, although such representations would have no use other than to define the result of sizeof?

Changing the promotion rules for bit-fields wider than int to avoid such expressions of bit-field type would create an odd inconsistency in the type system about which types are promoted, although it would be consistent with C++ where bit-fields have narrow representation but are considered to have the declared type rather than a special narrow type and would allow implementations to support bit-fields wider than int without needing special support for arithmetic on such types (alternatively, it could be argued that if an implementor wishes to support bit-fields wider than int it is up to them to implement arithmetic on all bit-field types wider than int as a consequence of their decision); changing the C definition of bit-field types to follow the C++ one would be more radical and probably not suitable for a TC. (C++ then has a special rule so that unsigned int bit-fields promote to int if narrower than int.) The alternative is to be more explicit about the nature of bit-field types and to define when an expression has such a type, and to make the constraint on sizeof apply to expressions with such types and not just to bit-fields themselves.

Suggested Technical Corrigendum


Comment from WG14 on 2007-10-10:

Committee Discussion (for history only)

Fall 2005 discussion

This defect report has been move back to open, to liaison with C++ - 2005-09-28

The Committee decision was to withdraw the answers to 2 and 3, see 6.3.1.1;p2.

Question 1: Must bit-fields of type char nevertheless have the same signedness as ordinary objects of type char, and similarly for those of types short (or short int), long (or long int), long long (or long long int)?

This is unspecified in the Standard - No.

Question 2: But what should sizeof(int) evaluate to, when (x.a + x.b) has such a bit-field type which does not occupy an integer number of bytes?

It must be something larger than int.

Question 3: Must an implementation define representations occupying an integer number of bytes (with some padding bits) for all such types, although such representations would have no use other than to define the result of sizeof?

Yes.

Spring 2006 discussion

Consider this relevant citation:

6.3.1.1 Boolean, characters, and integers

2 The following may be used in an expression wherever an int or unsigned int may be used:

— An object or expression with an integer type whose integer conversion rank is less than or equal to the rank of int and unsigned int.

— A bit-field of type _Bool, int, signed int, or unsigned int.

If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.48) All other types are unchanged by the integer promotions. 48) The integer promotions are applied only: as part of the usual arithmetic conversions, to certain argument expressions, to the operands of the unary +, -, and ~ operators, and to both operands of the shift operators, as specified by their respective subclauses.

This citation supports the committee's view that the type of a bit-field does not include the width; if int:7 were a type that is different from int, then these rules would not apply to any bit-field type, an obviously incorrect conclusion.

Question 1: Must bit-fields of type char nevertheless have the same signedness as ordinary objects of type char, and similarly for those of types short (or short int), long (or long int), long long (or long long int)?

These are all determined by the implementation-defined behavior specified in 6.7.2.1#4.

Question 2: But what should sizeof(x.a + x.b) evaluate to, when (x.a + x.b) has such a bit-field type which does not occupy an integer number of bytes?

In the example presented above, the type is unsigned long long, and it does occupy an integral number of bytes. The expression evaluates to sizeof(unsigned long long).

Note: This DR was marked to move into Review status after the Spring 2006 meeting. However, the document voted on at the Spring 2006 meeting had no Proposed text only Discussion text. The Editor decided to leave the DR as Open and allow the Committee to decide on the Proposed text for this DR at the Fall 2006 meeting.

Fall 2006 discussion

Question 1: Must bit-fields of type char nevertheless have the same signedness as ordinary objects of the char, and similarly for those of types short (or short int), long (or long int), long long (or long long int)?

these would all be implementation-defined, determined by the implementation-defined behavior specified in 6.7.2.1#4.

Question 2: But what should sizeof(x.a + x.b) evaluate to, when (x.a + x.b)has such a bit-field type which does not occupy an integer number of bytes?

In example presented above, this would be implementation-defined, determined by the implementation-defined behavior specified in 6.7.2.1#4.

Proposed Technical Corrigendum

Last sentence of paragraph 2 of 6.3.1.1, add the words as restricted by the width, for a bit-field as follows:

If an int can represent all values of the original type (as restricted by the width, for a bit-field), the type is converted to an int;



Issue 0316: Unprototyped function types

Authors: Joseph Myers <joseph@codesourcery.com>, UK C Panel
Date: 2005-03-04
Reference document: ISO/IEC WG14 N1104
Status: Closed
Cross-references: 0255
Converted from: summary-c99.htm, dr_316.htm

Summary

The rules for compatibility of function types in 6.7.5.3#15 do not define when a function type is "specified by a function definition that contains a (possibly empty) identifier list", and do not address compatibility between two types with that property or what the composite type is in such cases.

As a first example, consider:

        void f(a)int a;{}
        void g(a,b)int a,b;{}
        void (*h)(int, int, int) = (0 ? f : g);

What is the type of (0 ? f : g)? The types of f and g are compatible. Does (0 ? f : g) have a type specified by a function definition? Does (0 ? f : f)?

Question 1: Is the above translation unit valid?

Another example is:

        void f(a)int a;{}
        void (*h)(int, int, int) = f;

I believe the intent of the standard is that a type is specified by a function definition only for the purposes of checking compatibility of multiple declarations of the same function; when as here the name of the function appears in an expression, its type is determined by its return type and contains no trace of the parameter types. However, implementation interpretations vary.

Question 2: Is the above translation unit valid?

It may still be necessary for compatibility of multiple unprototyped function types determined by function definitions to be considered, if those definitions are in different translation units and all but one are inline. (As an aside, while the text of 6.7.4#6 assumes that there is only one definition of a function in a translation unit, I can find nothing prohibiting more if inline is used, though the presumption would probably mean compile-time undefined behavior if there were more than one in a translation unit, with compatible types.) By way of example, consider the following three translation units:

        // TU 1:
        inline void f(a)int a;{}

        // TU 2:
        inline void f(a,b)int a,b;{}

        // TU 3:
        void f(a,b,c)int a,b,c;{}

The function types seem to be compatible, so 6.2.7#2 does not apply.

Question 3: Must a program containing these three translation units, which never calls the function f, be accepted?

The function f cannot be called above from TU 1 or TU 2 without undefined behavior, but could be called from TU 3, where the inline definitions in TU 1 and TU 2 cannot be used for a call. (Though a program containing calls in TU 1 and TU 2 which are conditioned by if (0) would also seem to be valid.) In the following case, the types are similar enough that it would seem possible for calls to occur in all three translation units without undefined behavior (by virtue of the exceptions in 6.5.2.2#6):

        // TU 1:
        inline void f(a,b)int a;unsigned b;{}
        void g(void){f(0,0);}

        // TU 2:
        inline void f(a,b)unsigned a;int b;{}
        void h(void){f(0,0);}

        // TU 3:
        void f(a,b)int a,b;{}
        void i(void){f(0,0);}

Question 4: Must a program containing these three translation units be accepted?

It seems undesirable for such variation among the types of functions with inline definitions to be permitted. This could be fixed by defining compatibility of multiple unprototyped function definitions to require compatibility of the parameter types.

Suggested Technical Corrigendum


Comment from WG14 on 2006-03-05:

Committee Discussion (for history only)

The Committee believe the answers to Q1 & 2 are yes, and that the Standard is unclear with respect to 3 & 4.

Committee Response

Per the response provided in DR 255:

"The Committee does not wish to further refine the behavior of calls not in the scope of prototypes. In practice, this will not be a problem, and the Committee does not wish to define the behavior."

We have no intention of fixing the old style rules. However, the observations made in this document seem to be generally correct.



Issue 0317: Function definitions with empty parentheses

Authors: Joseph Myers <joseph@codesourcery.com>, UK C Panel
Date: 2005-03-04
Reference document: ISO/IEC WG14 N1105
Status: Closed
Converted from: summary-c99.htm, dr_317.htm

Summary

I believe the intent of C is that old-style function definitions with empty parentheses do not give the function a type including a prototype for the rest of the translation unit. For example,

void f(){}
void g(){if(0)f(1);}

is valid.

6.9.1#7 specifies that if the declarator in the function definition includes a parameter type list, it also serves as a prototype for the rest of the translation unit. It does not specify that nothing else serves as a prototype. Some readers of the standard interpret 6.7.5.3#14, "An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters.", as specifying that it provides a prototype.

Question 1: Does such a function definition give the function a type including a prototype for the rest of the translation unit?

Question 2: Is the above translation unit valid?

Suggested Technical Corrigendum


Comment from WG14 on 2006-04-04:

Committee Response

The grammar states that an empty parens stands for an empty identifier list not an empty parameter-type-list.

The answer to question #1 is NO, and to question #2 is YES. There are no constraint violations, however, if the function call were executed it would have undefined behavior. See 6.5.2.2;p6.



Issue 0318: (double)0.1f with FLT_EVAL_METHOD being 2

Authors: WG 14, Fred Tydeman (USA)
Date: 2004-10-27
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_318.htm

Summary

When FLT_EVAL_METHOD is 2, the 0.1f is represented to the precision of long double, while the type remains as float. Then, when the cast to double is done, contradictory requirements are specified by the standard. One part of the standard requires that when a float is promoted to a double, the value is unchanged. While another part of the standard requires that extra precision be removed by the cast conversion.

Details

5.2.4.2.2 Characteristics of floating types <float.h>; Paragraph 7 [after DR 290]

Except for assignment and cast (which remove all extra range and precision), the values of operations with floating operands and values subject to the usual arithmetic conversions and of floating constants are evaluated to a format whose range and precision may be greater than required by the type. The use of evaluation formats is characterized by the implementation-defined value of FLT_EVAL_METHOD:19)

2 evaluate all operations and constants to the range and precision of long double type.

6.3.1.5 Real floating types; Paragraphs 1 and 2

When a float is promoted to double or long double, or a double is promoted to long double, its value is unchanged.

When a double is demoted to float, a long double is demoted to double or float, or a value being represented in greater precision and range than required by its semantic type (see 6.3.1.8) is explicitly converted to its semantic type, if the value being converted can be represented exactly in the new type, it is unchanged. If the value being converted is in the range of values that can be represented but cannot be represented exactly, the result is either the nearest higher or nearest lower representable value, chosen in an implementation-defined manner. If the value being converted is outside the range of values that can be represented, the behavior is undefined.

6.3.1.8 Usual arithmetic conversions; Paragraph 2

The values of floating operands and of the results of floating expressions may be represented in greater precision and range than that required by the type; the types are not changed thereby. 52)

52) The cast and assignment operators are still required to perform their specified conversions as described in 6.3.1.4 and 6.3.1.5.

6.5.4 Cast operators; Paragraph 4

... A cast that specifies no conversion has no effect on the type or value of an expression. 86)

86) If the value of the expression is represented with greater precision or range than required by the type named by the cast (6.3.1.8), then the cast specifies a conversion even if the type of the expression is the same as the named type.

Suggested Technical Corrigendum

Add to 6.3.1.5, the end of paragraph 1: "(if the source value is represented in the precision and range of its type)".

Change in 6.3.1.5, paragraph 2, "explicitly converted to its semantic type" to "explicitly converted (including to its own type)".

Move the text of footnote 86 to normative text in 6.5.4.

An alternative (not liked by the author) is to add a footnote to 6.3.1.5 along the lines of: To force a floating-point value to have no more precision than a given type requires two casts to that type, e.g., (double)(double)0.1f assuredly has no more precision than (double). The rightmost cast changes the type, but not the representation, while the leftmost cast changes the representation (throws away any extra precision or range).


Comment from WG14 on 2006-03-05:

Technical Corrigendum

Add to 6.3.1.5, the end of paragraph 1:

"(if the source value is represented in the precision and range of its type)".

Change in 6.3.1.5, paragraph 2,

"explicitly converted to its semantic type" to "explicitly converted (including to its own type)".

Move the text of footnote 86 to normative text in 6.5.4.



Issue 0319: printf("%a", 1.0) and trailing zeros

Authors: WG 14, Fred Tydeman (USA)
Date: 2005-04-04
Reference document: ISO/IEC WG14 N1094
Status: Closed
Converted from: summary-c99.htm, dr_319.htm

Summary

Given that FLT_RADIX is 2, what is the output of:

  double x = 1.0;
  printf("%a", x);

In particular, are trailing zeros removed or kept?

Some choices that occur to me are:

  1. use the smallest precision for an exact representation of this particular value; in effect, remove trailing zeros.
  2. use the smallest precision for an exact representation of all values of this type; in effect, keep trailing zeros.
  3. use the smallest precision for an exact representation of all values of all floating-point types; in effect, promote to long double and keep trailing zeros.
  4. implementation defined.
  5. unspecified.
  6. something else.

Some implementations that I have seen do 1, others do 2, and one does both 1 and 2 (value and format dependent). I believe choice 1 is the intended behaviour.

Another way to look at this is: should %a act like %e (keep trailing zeros) or %g (remove trailing zeros) with respect to trailing zeros? Should this behaviour depend upon the user specifing a precision?

Some parts of 7.19.6.1 The fprintf function that are relavent are:

Paragraph 6 on the '#' flag has: "For g and G conversions, trailing zeros are not removed from the result."

Paragraph 8, section e,E, has: "... if the precision is zero and the # flag is not specified, no decimal-point character appears."

Paragraph 8, section g,G, has: "Trailing zeros are removed from the fractional portion of the result unless the # flag is specified; a decimal-point character appears only if it is followed by a digit."

Paragraph 8, section a,A, has: "... if the precision is missing and FLT_RADIX is a power of 2, then the precision is sufficient for an exact representation of the value; ..."

Paragraph 8, section a,A, has: "... if the precision is missing and FLT_RADIX is not a power of 2, then the precision is sufficient to distinguish values of type double, except that trailing zeros may be omitted; ..."

There are corresponding sections for the wide character versions of the functions in 7.24.2.1 The fwprintf function.

Suggested Technical Corrigendum

Change 7.19.6.1 The fprintf function sections as follows.

Paragraph 6 on the '#' flag, change the above to: "For a, A, g and G conversions, trailing zeros are not removed from the result."

Paragraph 8, section a,A, change the above to: "... if the precision is missing and FLT_RADIX is a power of 2, then the precision is the minimum sufficient for an exact representation of all values of type double (removal of trailing zeros depends upon the # flag); ..."

Paragraph 8, section a,A, change the above to: "... if the precision is missing and FLT_RADIX is not a power of 2, then the precision is the minimum sufficient to distinguish values of type double (removal of trailing zeros depends upon the # flag); ..."

Also, update the corresponding sections for the wide character versions of the functions in 7.24.2.1 The fwprintf function.

Add to the Rationale in section 7.19.6.1: %a (without an explicit precision) acts like %g (removes trailing zeros), while %.*a (with an explicit precision) acts like %e (keeps trailing zeros). This was done to allow two forms of behaviour while using only one conversion specifier.


Comment from WG14 on 2006-04-04:

Committee Response

The Committee does not believe this is a defect, however the Committee may consider establishing a rule for removing or not removing trailing zeros at some point in the future.



Issue 0320: Scope of variably modified type

Authors: Willem Wakker
Date: 2005-05-02
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_320.htm

Summary

The first sentence of 6.7.5.2p2 seems to suggest that any ordinary identifier both block scope or function prototype scope and no linkage has a variably modified type. This is clearly wrong.

Suggested Technical Corrigendum

Rewrite the first sentence of 6.7.5.2p2 to read:

An ordinary identifier (as defined in 6.2.3) that has a variably modified type shall have either block scope or function prototype scope, and no linkage.


Comment from WG14 on 2006-04-04:

Technical Corrigendum

Change the first sentence of 6.7.5.2p2 to:

An ordinary identifier (as defined in 6.2.3) that has a variably modified type shall have either block scope and no linkage or function prototype scope.



Issue 0321: Wide character code values for members of the basic character set

Authors: Austin Group, Nick Stoughton (US)
Date: 2005-04-26
Reference document: DR_279, Austin Group Aardvark comment XBD ERN 53
Status: Fixed
Fixed in: C99 TC3
Cross-references: 0279, 0333
Converted from: summary-c99.htm, dr_321.htm

Summary

Originally, Standard C required ('x' == L'x') to hold true when x is a member of the basic character set. This restricted the implementation's choice of wchar_t encoding, and the changes made in response to DR 279 removed this restriction (published as change #58, on page 11 of TC2). However, there is a vast body of existing application code that relies on this formerly normative requirement for portability.

DR 279 suggested methods to relax the restriction that would make it easier for applications to continue to rely on the relationship between basic characters and their wide character equivalents. The POSIX community strongly urges WG14 to reconsider the change introduced in ISO/IEC 9899:1999 Technical Corrigendum 2 in response to DR 279.

Details

C99 7.17 paragraph 2 specified (before TC2) in part:

"...

   wchar_t

which is an integer type whose range of values can represent distinct codes for all members of the largest extended character set specified among the supported locales; the null character shall have the code value zero and each member of the basic character set shall have a code value equal to its value when used as the lone character in an integer character constant."

TC2 altered this text, removing the phrase:

" and each member of the basic character set shall have a code value equal to its value when used as the lone character in an integer character constant"

In the committee discussion for TC2, an alternative approach was proposed:

"...

   wchar_t

which is an integer type whose range of values can represent distinct codes for all members of the largest extended character set specified among the supported locales; the null character shall have the code value zero. Each member of the basic character set shall have a code value equal to its value when used as the lone character in an integer character constant if an implementation does not define __STDC_BTOWC_NEQ_WCTOB__."

The POSIX community, as represented by the Austin Group, would have preferred this solution. Without any method to determine if the restriction applies or not, all applications would be required to make changes that may have performance and efficiency impacts in order to maintain portability. The ISO/IEC 9945:2004 POSIX standard contains words derived from the ISO/IEC 9899:1999 standard:

wchar_t

Integer type whose range of values can represent distinct wide-character codes for all members of the largest character set specified among the locales supported by the compilation environment: the null character has the code value 0 and each member of the portable character set has a code value equal to its value when used as the lone character in an integer character constant.

In order to align with TC2, the Austin Group is proposing to change this to:

wchar_t

Integer type whose range of values can represent distinct wide-character codes for all members of the largest character set specified among the locales supported by the compilation environment: the null character has the code value 0 and each member of the portable character set has a code value equal to its value when used as the lone character in an integer character constant if an implementation does not define __POSIX_BTOWC_NEQ_WCTOB__."

However, the Austin Group also feels that such a change would be beneficial to all C language users, and not just to the POSIX community, and therefore respectfully suggests that if a future revision or technical corrigendum to ISO/IEC 9899 were to be published, a similar change (using __STDC_BTOWC_NEQ_WCTOB__ as the macro name) would help application developers understand when and where the restriction applies.

Suggested Technical Corrigendum

Suggestion 1 from DR279:

This change allows an implementation to deviate from the last part of 7.17 paragraph 2 if the macro __STDC_BTOWC_NEQ_WCTOB__ is predefined. This would not affect ASCII based systems, but would provide leeway for EBCDIC systems to process Unicode using C.

Change the last part of 7.17 paragraph 2 as follows:

"...

   wchar_t

which is an integer type whose range of values can represent distinct codes for all members of the largest extended character set specified among the supported locales; the null character shall have the code value zero. Each member of the basic character set shall have a code value equal to its value when used as the lone character in an integer character constant if an implementation does not define __STDC_BTOWC_NEQ_WCTOB__."

A program that requires the wchar_t restriction can check for the macro and cause the translator to put out a diagnostic if the implementation does not support the restriction. This at least would help diagnose porting problems.


Comment from WG14 on 2006-04-04:

Technical Corrigendum

Change the last part of 7.17 paragraph 2 as follows:

   wchar_t

which is an integer type whose range of values can represent distinct codes for all members of the largest extended character set specified among the supported locales; the null character shall have the code value zero. Each member of the basic character set shall have a code value equal to its value when used as the lone character in an integer character constant if an implementation does not define __STDC_MB_MIGHT_NEQ_WC__.



Issue 0322: Problem with TC2 Change #67 (Add perror to the list defining byte input/output functions.)

Authors: Donald W. Cragun <don.cragun@sun.com>, Cragun (US)
Date: 2005-09-28
Reference document: Defect Report #276
Status: Fixed
Fixed in: C99 TC3
Cross-references: 0276
Converted from: summary-c99.htm, dr_322.htm

Summary

The perror function should not set the orientation of the standard error stream if the orientation is not already set.

Rationale

ISO/IEC 9899:1990 as updated by Amendment 1: C Integrity did not identify the perror function as a byte input/output function nor as a wide-character input/output function. Therefore, calling perror was not allowed to set the stream orientation for the standard error stream. Although no rationale was given in the amendment for not specifying perror in either set of functions, it seemed to be the appropriate behavior. We would like to be able to use perror at any time when an application needs to report an error condition. If perror was defined to be a byte output function or a wide-character output function and the standard error stream's orientation had been set to the opposite orientation, the standard requires that perror shall not be applied to the stream. Furthermore, as part of aligning with Amendment 1, The Single UNIX Specification, version 2's description of perror says:

The perror() function does not change the orientation of the standard error stream.

This quote was slightly transformed as Single UNIX Specification, version 2; IEEE Std 1003.1-1996 and IEEE Std 1003.2-1992; and ISO/IEC 9945-1:1996 and ISO/IEC 9945-2:1993 were merged to create the common Single UNIX Specification, version 3; IEEE Std 1003.1-2001; and ISO/IEC 9945-1, 9945-2, 9945-3, and 9945-4:2002 to be:

The perror() function shall not change the orientation of the standard error stream.

Therefore, the change in TC2 that turned perror into a byte input/output function created a conflict between the C standard and the POSIX standard.

If a fatal error arises and an application wants to use perror to print a diagnostic message, it is now required to be prepared to do something like:

save_errno = errno;
    or = fwide(stderr, 0);
    errno = save_errno;
    perror("error identifying string")
    freopen("", "w", stderr);
    fwide(stderr, or);

rather than just calling perror. Note that calling freopen with a null pointer as its first argument did not have defined behavior in the previous C standard and was required to give an ENOENT error in the previous revision of the POSIX standard. Furthermore, if the standard error stream had been wide-character oriented before the call to freopen, no application reading that stream would know that it needed to switch input methods when the orientation switched back to byte orientation for the diagnostic. So, not changing orientation and just printing byte oriented diagnostic messages would not seem to make any difference to any application that was later trying to read bytes that had been written to the standard error stream.

If it is believed that perror really needs to be classified as a byte output function, maybe it should also be specified that applications that use any wide-character input/output functions on the standard error stream produce undefined behavior (especially if they call perror).

Suggested Technical Corrigendum

Rescind ISO/IEC 9899:1999/Cor.2:2004 change #67 which states:

Page 263, 7.19.6.1
In paragraph 5, item 4, insert perror after gets.


Comment from WG14 on 2006-10-25:

Committee Discussion (for history only)

The Committee discussed making the behavior undefined, which would allow perror() to fail if the stream orientation has already been set to wide.

The proposed TC will permit (but not require) perror to set the orientation of an un-oriented stderr to narrow, and has what C calls undefined behavior if stderr was previously set to wide. This permits the POSIX required behavior.

Technical Corrigendum

Rescind ISO/IEC 9899:1999/Cor.2:2004 change #67 which states:

Page 263, 7.19.1
In paragraph 5, item 4, insert perror after gets.



Issue 0323: Potential problems with TC2 #34, #35, and #36

Authors: Josey (US)
Date: 2005-09-28
Reference document: N1138
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_323.htm

Summary: The imaginary macro is missing in the normative text.

I think there may be a problem here with C99 (as amended by TC2). As far as I can see there is no longer any mention of the imaginary macro in normative text, which means implementations are not allowed to define it (because it is not reserved for use by the implementation). Yet in Annex G it still recommends (in informative text) that implementations which define __STDC_IEC_559_COMPLEX__ should define the imaginary macro. It also recommends that these implementations should define I "to be _Imaginary_I (not _Complex_I as stated in 7.3)". Yet implementations that do so would not comply with the normative text in 7.3 which requires I to be defined as _Complex_I.

Assuming that the intention was to allow implementations to follow the recommendations in Annex G, but by an oversight the necessary normative text to allow them to do so was omitted from TC2, perhaps in POSIX we should keep the current text but mark some of it CX?

Suggested Technical Corrigendum


Comment from WG14 on 2006-10-25:

Committee Discussion (for history only)

Fall 2005 discussion

It was pointed out that implementing Annex G causes nonconforming changes to the normative text in C99. Exact instances were not given or known. The implications of NOT allowing 'I' to expand to '_Imaginary_I' are not readily clear.

Spring 2006 discussion

We did not fully realize the repercusions of the changes that DR 207 would do (implementing Annex G and

make the implementation non-conforming; our intent was to allow implementations to do Annex G and still conform) and agree that (some of) the effects of DR 207 should be undone. There are three possible levels of undo that could be done.

  1. The smallest one is back out parts of DR 207 so that C99 allows Annex G implementators to define the imaginary macro and have I to _Imaginary_I and still conform.
  2. The middle one is restore C99 back to the state before DR 207 was applied.
  3. The hardest one is to re-process DR 207 and look at the suggested alternate changes it has (and even other imaginary issues identified).

Some members of the committee had hoped that imaginary would be ignored and go away. However, at least one vendor has shipped an implementation that supports imaginary and Annex G. This vendor has indicated that it would not be hard to modify its implementation so that it passes strict conformance with one command line switch and offer a default implementation with imaginary without that switch.

One problem with I being imaginary versus complex is f(I) is either passed one double or two doubles. However, this only matters to a few type generic math functions and no user functions (since users have no means to define their own type generic functions). One such type generic math function is cosh(), i.e., cosh(I*y) is the real cos(y) if I is imaginary, but is the complex cosh(z) if I is complex.

It has been observed that the relational operators (<, <=, >=, >) of 6.5.8 and comparison macros of 7.12.14 (isless, ...) should be allowed to be used with imaginary types when both operands are imaginary; this was an oversite in the original C99 specification.

The mimimal changes to restore back to C99 w.r.t. to DR 207 is restore paragraphs 3, 4, and 5 of 7.3.1 of C99; this is a subset of the changes done by DR 207 in TC2.

Technical Corrigendum

In 7.3.1 of C99+TC1+TC2, replace paragraphs 3 and 4 with:

[#3] The macros

imaginary

and

_Imaginary_I

are defined if and only if the implementation supports imaginary types;165 if defined, they expand to _Imaginary and a constant expression of type const float _Imaginary with the value of the imaginary unit.

[#4] The macro

I

expands to _Imaginary_I or _Complex_I. If _Imaginary_I is not defined, I shall expand to _Complex_I.

[#5] Notwithstanding the provisions of subclause 7.1.3, a program may undefine and perhaps then redefine the macros complex, imaginary and I.

165A specification for imaginary types is in informative annex G.



Issue 0324: Tokenization obscurities

Authors: Ivan A. Kosarev (Unicals Group, RU)
Date: 2005-04-19
Reference document: N1123
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_324.htm

Summary #1

5.1.1.2 #2 ("Translation phases") says:

[#2] ...2. Each instance of a backslash character (\) immediately followed by a new-line character is deleted, splicing physical source lines to form logical source lines. Only the last backslash on any physical source line shall be eligible for being part of such a splice. A source file that is not empty shall end in a new-line character, which shall not be immediately preceded by a backslash character before any such splicing takes place.

3. The source file is decomposed into preprocessing tokens6) and sequences of white-space characters (including comments). A source file shall not end in a partial preprocessing token or in a partial comment. Each comment is replaced by one space character. New-line characters are retained. Whether each nonempty sequence of white-space characters other than new-line is retained or replaced by one space character is implementation-defined.

Assuming there is a non-empty source file legally ending with a new-line character, what are examples of such partial preprocessing tokens that could end the file? And, generally, what the partial preprocessing tokens are?

Summary #2

6.4.4.4 ("Character constants") says:

[#3] The single-quote ', the double-quote ", the question-mark ?, the backslash \, and arbitrary integer values are representable according to the following table of escape sequences...

[#5] The octal digits that follow the backslash in an octal escape sequence are taken to be part of the construction of a single character for an integer character constant or of a single wide character for a wide character constant...

[#6] The hexadecimal digits that follow the backslash and the letter x in a hexadecimal escape sequence are taken to be part of the construction of a single character for an integer character constant or of a single wide character for a wide character constant...

[#8] In addition, characters not in the basic character set are representable by universal character names and certain nongraphic characters are representable by escape sequences consisting of the backslash \ followed by a lowercase letter: \a, \b, \f, \n, \r, \t, and \v.64)

64) The semantics of these characters were discussed in 5.2.2. If any other character follows a backslash, the result is not a token and a diagnostic is required. See “future language directions” (6.11.4).

6.4 #3 ("Lexical elements") says:

[#3] ...The categories of preprocessing tokens are: header names, identifiers, preprocessing numbers, character constants, string literals, punctuators, and single non-white-space characters that do not lexically match the other preprocessing token categories.58) If a ' or a " character matches the last category, the behavior is undefined.

What in the formal content of the standard says that if any other character follows a backslash, there should be a diagnostic? Does such a case causes undefined behaviour? Furthermore, if a character sequence that is coming just after a double quote " (that is not terminating a string literal) begins with, say, \l and the result of the tokenization is not a token, then what the result is?

Summary #3

6.10.9 #2 ("Pragma operator") gives the following example:

[#2] EXAMPLE A directive of the form:

#pragma listing on "..\listing.dir"

can also be expressed as:

_Pragma ( "listing on \"..\\listing.dir\"" )

The previous summary says that if there an unknown escape sequence encountered during tokenization of a character constant or string literal, then the result is not token. The question is whether the example above is well-defined.

Suggested Technical Corrigendum


Comment from WG14 on 2006-10-25:

Proposed Committee Response

Answers to Summary #1

"Partial preprocessing token" is not itself a technical term; it is merely the English Language word "partial" modifying the technical term "preprocessing token". A preprocessing token is defined by the grammar non-terminal preprocessing-token in Subclause 6.4. A partial preprocessing token is therefore just part of a preprocessing token that is not the entire preprocessing token.

The statement that "source files shall not end in a partial preprocessing token or in a partial comment" has two implications. First, a preprocessing token may not begin in one file and end in another file. Second, the last preprocessing token in a source file must be well-formed and complete. For example, the last token may not be a string literal missing the close quote.

Answers to Summary #2

Subclause 5.1.1.3 requires a diagnostic to be produced if there is a violation of any syntax rule or constraint. The syntax for character constants (Subclause 6.4.4.4) and string literals (Subclause 6.4.5) both require that any escape sequence be well formed according the nonterminal escape-sequence (Subclause 6.4.4.4). Thus a diagnostic is required if a character constant or string literal contains a \ not followed by the remainder of a valid escape sequence.

Note that a preprocessor token may be a header-name in addition to a string-literal. Although a header-name has the appearance of a string literal, it is parsed by a different grammar (Subclause 6.4.7). The syntax for header-name is not violated if a \ is not followed by the remainder of a valid escape sequence. Thus, no diagnostic is required. However, if a header name contains a \, the behavior is undefined (Subclause 6.4.7, paragraph 3).

Since the behavior is undefined, the implementation is free to do anything it wishes. Some possible examples:

The last alternative is useful if your operating system normally uses \ in the names of files.

Answers to Summary #3

Before your question can be answered, it is necessary to understand the precise steps taken in translating a _Pragma operator as controlled by the phases of translation (Subclause 5.1.1.2).

The _Pragma operator (Subclause 6.10.9) has an argument that is a string literal. If any escape sequence in that string literal is not grammatically well-formed, a diagnostic is required. In the example, the string literal is syntactically correct, so no diagnostic is required so far.

The _Pragma operator is executed during translation phase 4. Note that escape sequences in a string are not replaced by the characters that they represent until translation phase 5. However, the _Pragma operator itself does limited processing to handle \\ and \" escape sequences (Subclause 6.10.9 paragraph 1), and so when the value of the string literal is retokenized to produce preprocessor tokens, the result for the example matches the #pragma directive given.

The final answer to your question rests with whether the preprocessor tokens in the #pragma directive require a diagnostic. Subclause 6.10.6 states that a #pragma directive ends in just a list of preprocessor tokens without placing any requirements on which preprocessor tokens.

Your question then becomes whether the preprocessor token that looks like a string in the #pragma in the example is a string-literal or a header-name. If it is a string-literal, a diagnostic is required. If it is a header-name, no diagnostic is required, but there is undefined behavior. The choice of which preprocessor tokens are allowed in a #pragma directive is implementation defined.

Subclause 6.10.9 paragraph 1 states that a #pragma causes the implementation to behave in an implementation-defined manner including the possibility that the implementation might fail or otherwise behave in a non-conforming manner. The intent of the committee was that implementations could recognize header-name preprocessor tokens in #pragma directives, if the implementation chooses, but this seems to be contradicted by the two places requiring Technical Corrigenda below.

Technical Corrigendum

Change Subclause 6.4.7, paragraph 3, last sentence to:

Header name preprocessing tokens are recognized only within #include preprocessing directives or in implementation-defined locations within #pragma directives*).

(* New Footnote): For an example of a header name preprocessing token used in a #pragma directive, see Subclause 6.10.9.

Change Subclause 6.4, paragraph 4, last sentence to:

There is one exception to this rule: Header name preprocessing tokens are recognized only within #include preprocessing directives or in implementation-defined locations within #pragma directives. In such contexts, a sequence of characters that could be either a header name or a string literal is recognized as the former.



Issue 0325: strerror()

Authors: Stoughton (US)
Date: 2006-03-20
Reference document: XSH Aardvark, ERN 137
Status: Closed
Converted from: summary-c99.htm, dr_325.htm

Summary: Is an implementation permitted to return an empty string for strerror()?

This is a potential defect forwarded from the Austin Group. Is an implementation of strerror permitted to return an empty string if there is no associated error message for the given errnum?

The C Standard, although not perfectly clear, strongly implies that the string returned by strerror() cannot be empty. The C Standard says

strerror shall map any value of type int to a message.

It doesn't state that the message cannot be empty, but the fact that it uses the word "message" means that any interpretation that allows this message to be empty would also have to allow the diagnostic messages produced by the compiler to be empty. Clearly such an interpretation is very much not intended. Note that the relationship between the term "diagnostic message" and the "message" produced by strerror() is clear from section 3.10:

diagnostic message
message belonging to an implementation-defined subset of the implementation's message output

On the other hand, some have argued that "An implementation-defined subset" does not preclude the empty string from being included in the set of messages, provided the implementation has defined the error that equates to the message.

Suggested Technical Corrigendum

Clarification Required.

Change 7.21.6.2, p2 from:

The strerror function maps the number in errnum to a message string. Typically, the values for errnum come from errno, but strerror() shall map any value of type int to a message.

To:

The strerror function maps the number in errnum to a message string. If the value of errnum is a valid error number, the message string shall indicate what error occurred; otherwise, if this functions completes successfully, the message string shall indicate that an unknown error occurred. Typically, the values for errnum come from errno, but strerror shall map any value of type int to a message.


Comment from WG14 on 2006-10-25:

Proposed Committee Response

The intention is to allow implementations to decide what form of message is appropriate. There is no consensus to make the suggested change or any change along this line.



Issue 0326: asctime()

Authors: The Austin Group, Stoughton (US)
Date: 2006-03-28
Reference document: AI-053.txt, DR 217
Status: Fixed
Fixed in: C11
Cross-references: 0217
Converted from: summary-c99.htm, dr_326.htm

Summary: asctime() tm_year gt 9999

This is a potential defect forwarded from the Austin Group.

If asctime() is called with a tm structure whose tm_year field results in a year > 9999 (which is possible with 64-bit time_t), the current specification of asctime() would result in asctime() to overrunning a 26-character buffer; the specification says the sprintf() format for printing the year is "%d", and (eg) a 5-digit number would print 5 characters, overrunning the buffer.

Similarly, since the user can create the input struct tm, it is possible for the user to set the fields of the struct tm to values that are outside the normal bounds. In such a case, the sprintf() format given in the asctime() specification can result in a buffer overrun. For example, if tm_hour is 100, the sprintf() format .2d writes the string "100", which could result in a buffer overrun. The specification should be updated to state the algorithm can be used as long as the values of the tm struct are restricted to the normal bounds.

Suggested Technical Corrigendum

Change 7.23.3.1 para 2 from:

The asctime function converts the broken-down time in the structure pointed to by timeptr into a string in the form:

To:

The asctime() function shall convert the broken-down time in the structure pointed to by timeptr into a string in the form, provided the broken-down time in the fields of the structure pointed to by timeptr contain values that are within the normal ranges as defined in <time.h>, and the calculated year does not exceed four digits:

(NB, see 7.23.1 para 4 for the specifications of the "normal ranges").

Also, add after the example code, and before the "Returns" section, the following new paragraph:

Otherwise, if any of the fields of the tm structure pointed to by timeptr contain values that are outside the normal ranges, the behavior of asctime() is undefined. If the calculated year exceeds four digits, the behavior is undefined.


Comment from WG14 on 2007-09-06:

Committee Discussion (for history only)

The proposed resolution invalidates code that strictly conforms to the C99 standard. Here is a contrived example (though there are some examples that are not contrived):

   #include <time.h>
   #include <stdio.h>

   struct tm tm;

   int
   main (void)
   {
     tm.tm_wday = 0;
     tm.tm_mon = 0;
     tm.tm_mday = -99;
     tm.tm_hour = 99;
     tm.tm_min = 99;
     tm.tm_sec = 99;
     tm.tm_year = -999 - 1900;
     printf ("%s\n", asctime (&tm));
     return 0;
   }

This code strictly conforms to C99, with well-defined behavior, and some implementations prints "Sun Jan-99 99:99:99 -999". The proposed resolution places extra constraints on asctime's arguments that would cause the above code to have undefined behavior.

The original interpretation request considered by the Austin Group contained an additional requirement, that the calculated year should not precede the Epoch (the date and time associated with (time_t)0). This restriction was removed in forwarding this to the C committee, since there is no C equivalent concept. However, if the calculated year is less than 1000, problems may occur, so perhaps the wording should be:

If the calculated year is less than 1000 or greater than 9999, the behavior is undefined.

Note: This appears to be a duplicate of DR 217, which advises no consensus / no change.

It was also pointed out that the Proposed Technical Corrigendum does not fix all of the issues, such as if tm_mon=4 and tm_mday=31, both valid numbers, but not a valid date.

Technical Corrigendum

Add after the example code, and before the "Returns" section, the following new paragraph:

If any of the fields of the tm structure pointed to by timeptr contain values that are outside the normal ranges*, the behavior of asctime() is undefined. If the calculated year exceeds four digits, or is less than the year 1000, the behavior is undefined.

Add footnote *:

See 7.23.1 para 4 for the specifications of the "normal ranges".



Issue 0327: Italicize definition of variable length array type, add forward references

Authors: Rich Peterson <Rich.Peterson@hp.com>, J11
Date: 2006-03-29
Status: Fixed
Fixed in: C11
Converted from: summary-c99.htm, dr_327.htm

Summary

The definition of variable length array type is in 6.7.5.2p4 (Array declarators), but it is not italicized:

If the size is * instead of being an expression, the array
type is a variable length array type of unspecified size,
which can only be used in declarations with function prototype
scope; such arrays are nonetheless complete types. If the size
is an integer constant expression and the element type has a
known constant size, the array type is not a variable length
array type; otherwise, the array type is a variable length
array type.

The way that the term appears in the text is not in a form where there is a single occurrence that gives the complete definition, but it would still probably be better to italicize it than not.

Or perhaps both the 1st and 3rd occurrence of it in the above should get italics?  It would not make sense to italicize the 2nd occurrence.  Re-writing the text to create a single occurrence that provides a complete definition does not seem worthwhile.

Also, variable length array types are mentioned several times prior to this definition.  The following sections should probably have a forward reference "variable length array type (6.7.5.2)":  6.2.4, 6.2.7, 6.5.3.4

Similarly, a forward reference "variably modified type (6.7.5)" is desirable in  6.7.2.1.

Suggested Technical Corrigendum

1. Change first sentence of 6.7.5.2p4 (adding italics) from::

If the size is * instead of being an expression, the array type is a variable length array type of unspecified size, which can only be used in declarations with function prototype scope; such arrays are nonetheless complete types.

to

If the size is * instead of being an expression, the array type is a variable length array type of unspecified size, which can only be used in declarations with function prototype scope; such arrays are nonetheless complete types.

It might also be desirable to change the second sentence (adding italics) from:

If the size is an integer constant expression and the element type has a known constant size, the array type is not a variable length array type; otherwise, the array type is a variable length array type.

to

If the size is an integer constant expression and the element type has a known constant size, the array type is not a variable length array type; otherwise, the array type is a variable length array type.

2. Change list of Forward references following 6.2.4p6 from

Forward references: statements (6.8), function calls (6.5.2.2), declarators (6.7.5), array declarators (6.7.5.2), initialization (6.7.8).

to

Forward references: statements (6.8), function calls (6.5.2.2), declarators (6.7.5), array declarators (6.7.5.2), variable length array type (6.7.5.2), initialization (6.7.8).

3. Add forward reference section following 6.2.7p5:

Forward references: variable length array type (6.7.5.2).

4. Change list of Forward references following 6.5.3.4p7 from:

Forward references: common definitions <stddef.h> (7.17), declarations (6.7), structure and union specifiers (6.7.2.1), type names (6.7.6), array declarators (6.7.5.2).

to

Forward references: common definitions <stddef.h> (7.17), declarations (6.7), structure and union specifiers (6.7.2.1), type names (6.7.6), array declarators (6.7.5.2), variable length array type (6.7.5.2).

5. Change list of Forward references following 6.7.2.1p22 from:

Forward references: tags (6.7.2.3).

to

Forward references: tags (6.7.2.3), variably modified type (6.7.5).


Comment from WG14 on 2007-09-06:

Technical Corrigendum

1. Change first sentence of 6.7.5.2p4 (adding italics) from::

If the size is * instead of being an expression, the array type is a variable length array type of unspecified size, which can only be used in declarations with function prototype scope; such arrays are nonetheless complete types.

to

If the size is * instead of being an expression, the array type is a variable length array type of unspecified size, which can only be used in declarations with function prototype scope; such arrays are nonetheless complete types.

2. Change the second sentence (adding italics) from:

If the size is an integer constant expression and the element type has a known constant size, the array type is not a variable length array type; otherwise, the array type is a variable length array type.

to

If the size is an integer constant expression and the element type has a known constant size, the array type is not a variable length array type; otherwise, the array type is a variable length array type.

3. Change list of Forward references following 6.2.4p6 from

Forward references: statements (6.8), function calls (6.5.2.2), declarators (6.7.5), array declarators (6.7.5.2), initialization (6.7.8).

to

Forward references: statements (6.8), function calls (6.5.2.2), declarators (6.7.5), array declarators (6.7.5.2), variable length array type (6.7.5.2), initialization (6.7.8).

4. Add forward reference section following 6.2.7p5:

Forward references: variable length array type (6.7.5.2).

5. Change list of Forward references following 6.5.3.4p7 from:

Forward references: common definitions <stddef.h> (7.17), declarations (6.7), structure and union specifiers (6.7.2.1), type names (6.7.6), array declarators (6.7.5.2).

to

Forward references: common definitions <stddef.h> (7.17), declarations (6.7), structure and union specifiers (6.7.2.1), type names (6.7.6), array declarators (6.7.5.2), variable length array type (6.7.5.2).

6. Change list of Forward references following 6.7.2.1p22 from:

Forward references: tags (6.7.2.3).

to

Forward references: tags (6.7.2.3), variably modified type (6.7.5).



Issue 0328: String literals in compound literal initialization

Authors: <whyglinux@gmail.com>, Project Editor (Larry Jones)
Date: 2006-06-03
Status: Fixed
Fixed in: C11
Cross-references: 0339
Converted from: summary-c99.htm, dr_328.htm

Summary

6.5.2.5 Compound literals, paragraph 3 in ISO/IEC 9899:1999 C Standard says:

If the compound literal occurs outside the body of a function, the initializer list shall consist of constant expressions.

This is to say a string literal, which is neither a constant nor a constant expression, can not be taken to initialize a compound literal with static storage duration. However, this is not the fact.

String literals can not be constants because they are not among constants (defined in Section 6.4.4). When a string literal is used to initialize a compound literal (in the case an array type), the array-to-pointer conversion does not occur (6.3.2.1 Lvalues, arrays, and function designators, paragraph 3), and hence the string literal can not be an address constant, which is the only chance to become a constant expression.

Obviously string literals should be mentioned together with constant expressions. It should be:

If the compound literal occurs outside the body of a function, the initializer list shall consist of constant expressions or string literals.

The following paragraph excerpted from Page 125, 6.7.8-4 seems to support the above correction:

All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.

Suggested Technical Corrigendum

Change 6.5.2.5, paragraph 3, to:

If the compound literal occurs outside the body of a function, the initializer list shall consist of constant expressions or string literals.


Comment from WG14 on 2007-10-10:

Proposed Technical Corrigendum

Replace 6.5.2.5 paragraph 2 and 3 to:

All the constraints for initializer lists in 6.7.8 are applicable to compound literals.

Change 6.5.2.5 paragraph 7 to:

All the semantic rules for initializers lists in 6.7.8 are applicable to compound literals.82)



Issue 0329: Math functions and directed rounding

Authors: Fred J. Tydeman, J11
Date: 2006-07-07
Reference document: N1181
Status: Fixed
Fixed in: C11
Converted from: summary-c99.htm, dr_329.htm

Summary:

Consider: remainder( DBL_MIN*(1.0+2.0*DBL_EPSILON), DBL_MIN*(1.0+DBL_EPSILON) )

The result is DBL_MIN*DBL_EPSILON, a subnormal number. But, if the implementation does not support subnormal numbers, such as IBM S/360 hex floating-point, then it is either zero or DBL_MIN, depending upon the current rounding direction mode. Hence, the sentence "Thus, the remainder is always exact." in footnote 204 in C99+TC1+TC2 (N1124) is wrong. This problem also applies to remquo and fmod.

After finding that flaw, I looked at the other math functions and their relationship to directed rounding. That search found several areas where things could be improved and one area (nextafter) that took an informal request for interpretation to the IEEE-754 committee to find the answer.

7.12.6.4 The frexp functions should be updated along the lines of:

When the radix of the argument is a power of 2, the returned value is exact and is independent of the current rounding direction mode.

7.12.6.5 The ilogb functions should be updated along the lines of:

When the returned value is representable in the range of the return type, the returned value is exact and is independent of the current rounding direction mode.

7.12.6.11 The logb functions should be updated along the lines of:

The returned value is exact and is independent of the current rounding direction mode.

7.12.6.12 The modf functions should be updated along the lines of:

The returned values are exact and are independent of the current rounding direction mode.

7.12.7.2 The fabs functions should be updated along the lines of:

The returned value is exact and is independent of the current rounding direction mode.

7.12.9.1 The ceil functions should be updated along the lines of:

The returned value is exact and is independent of the current rounding direction mode.

7.12.9.2 The floor functions should be updated along the lines of:

The returned value is exact and is independent of the current rounding direction mode.

7.12.9.8 The trunc functions should be updated along the lines of:

The returned value is exact and is independent of the current rounding direction mode.

7.12.10.1 The fmod functions should be updated along the lines of:

When subnormal results are supported, the returned value is exact and is independent of the current rounding direction mode.

7.12.10.2 The remainder functions should be updated along the lines of:

When subnormal results are supported, the returned value is exact and is independent of the current rounding direction mode.

7.12.10.3 The remquo functions should be updated along the lines of:

When subnormal results are supported, the returned value is exact and is independent of the current rounding direction mode.

7.12.11.1 The copysign functions should be updated along the lines of:

The returned value is exact and is independent of the current rounding direction mode.

7.12.11.2 The nan functions should be updated along the lines of:

The returned value is exact and is independent of the current rounding direction mode.

7.12.11.3 The nextafter functions should be updated along the lines of:

Even though underflow or overflow may happen, the returned value is independent of the current rounding direction mode.

7.12.11.4 The nexttoward functions should be updated along the lines of:

Even though underflow or overflow may happen, the returned value is independent of the current rounding direction mode.

7.12.12.2 The fmax functions should be updated along the lines of:

The returned value is exact and is independent of the current rounding direction mode.

7.12.12.3 The fmin functions should be updated along the lines of:

The returned value is exact and is independent of the current rounding direction mode.

F.9.4.5 The sqrt functions could be updated along the lines of:

The returned value is dependent on the current rounding direction mode.

Consider adding the following to section 7.12.1 (or make it its own section) of the Rationale.

There are several functions that are independent of the current rounding direction. Some are documented as such: round, lround, llround, remainder (when subnormal results are supported), remquo (when subnormal results are supported), nextafter (as per IEEE-754), and nexttoward (as per C99 and nextafter). Note, even though nextafter and nexttoward can raise underflow+inexact and overflow+inexact, they are not affected by the rounding direction.

Some are independent because they are exact: frexp (when radix is power of 2), logb, modf, ilogb, fabs, ceil, floor, trunc, fmod (when subnormal results are supported), copysign, nan, fmax, and fmin.

There are several functions that are dependent on the current rounding direction: sqrt (as per IEEE-754), nearbyint, rint, lrint, llrint, and fma.

There are many functions (it is implementation defined as to which ones) that may honor the current rounding direction. First are functions that are inexact for most arguments: acos, asin, atan, atan2, cos, sin, tan, acosh, asinh ,atanh, cosh, sinh, tanh, exp, exp2, expm1, frexp (when radix is not a power of 2), ldexp (when radix is not 2), log, log10, log1p, log2, hypot, pow, cbrt, erf, erfc, tgamma, lgamma, and fdim.

Second are functions that are exact for most arguments (but are inexact when they overflow or underflow): ldexp (when radix is 2), scalbn, scalbln, fmod (when subnormal results are not supported), remainder (when subnormal results are not supported), and remquo (when subnormal results are not supported).


Comment from WG14 on 2008-09-12:

Committee Discussion

These look like new requirements on the math functions (they are not). They might break an existing implementation (possible). Therefore, only add these to annex F.

The above material for the rationale, which should be used, should merge the last two paragraphs.

Fall 2007

It was noted that there is no rounding requirements for some of the cases mentioned

Spring 2008

We believe that the proposed TC is correct, and nobody has found any additional rounding requirements.

Technical Corrigendum

In section 7.12.10.2, remove the sentence "Thus, the remainder is always exact." in footnote 204 in C99+TC1+TC2.

F.9.3.4 The frexp functions add the following sentence:

When the radix of the argument is a power of 2, the returned value is exact and is independent of the current rounding direction mode.

F.9.3.5 The ilogb functions, add the following sentence:

When the returned value is representable in the range of the return type, the returned value is exact and is independent of the current rounding direction mode.

F.9.3.11 The logb functions, add the following sentence:

The returned value is exact and is independent of the current rounding direction mode.

F.9.3.12 The modf functions, add the following sentence:

The returned values are exact and are independent of the current rounding direction mode.

F.9.4.2 The fabs functions, add the following sentence:

The returned value is exact and is independent of the current rounding direction mode.

F.9.4.5 The sqrt functions, add the following sentence:

The returned value is dependent on the current rounding direction mode.

F.9.6.1 The ceil functions, add the following sentence:

The returned value is exact and is independent of the current rounding direction mode.

F.9.6.2 The floor functions, add the following sentence:

The returned value is exact and is independent of the current rounding direction mode.

F.9.6.8 The trunc functions, add the following sentence:

The returned value is exact and is independent of the current rounding direction mode.

F.9.7.1 The fmod functions, add the following sentence:

When subnormal results are supported, the returned value is exact and is independent of the current rounding direction mode.

F.9.7.2 The remainder functions, add the following sentence:

When subnormal results are supported, the returned value is exact and is independent of the current rounding direction mode.

F.9.7.3 The remquo functions, add the following sentence:

When subnormal results are supported, the returned value is exact and is independent of the current rounding direction mode.

F.9.8.1 The copysign functions, add the following sentence:

The returned value is exact and is independent of the current rounding direction mode.

F.9.8.2 The nan functions, add the following sentence:

The returned value is exact and is independent of the current rounding direction mode.

F.9.8.3 The nextafter functions, add the following sentence:

Even though underflow or overflow can occur, the returned value is independent of the current rounding direction mode.

F.9.8.4 The nexttoward functions, add the following sentence:

Even though underflow or overflow can occur, the returned value is independent of the current rounding direction mode.

F.9.9.2 The fmax functions, add the following sentence:

The returned value is exact and is independent of the current rounding direction mode.

F.9.9.3 The fmin functions, add the following sentence:

The returned value is exact and is independent of the current rounding direction mode.



Issue 0330: Externally visible exceptional conditions

Authors: Fred J. Tydeman, J11
Date: 2006-07-18
Reference document: N1183
Status: Fixed
Fixed in: C11
Converted from: summary-c99.htm, dr_330.htm

Summary

C99 7.12.1 Treatment of error conditions paragraph 1 has: Each function shall execute as if it were a single operation without generating any externally visible exceptional conditions.

As written, I believe that means that errno cannot be altered by any math function, nor can any of the floating-point exceptions mentioned later in 7.12.1 ("invalid", "divide-by-zero", "overflow", "underflow") be raised by any math function.

That was not our intent.

Seems to me that there are two problems with that text in 7.12.1:

Suggested Technical Corrigendum


Comment from WG14 on 2007-10-30:

Committee Discussion

In the Rationale, please add to section 6.5 Expressions, as a new paragraph, words along the lines of:

The "inexact" floating-point exception is NOT an exceptional condition because "inexact" arises from computing a mathematically defined value in the range of representable values, therefore, from the definition, "inexact" is not exceptional. This matters for spurious exceptional conditions in the math library (7.12.1).

Proposed Technical Corrigendum

Change 7.12.1 paragraph 1 last sentence to:

Each function shall execute as if it were a single operation without generating any of the exceptions "invalid", "divide-by-zero", or "overflow" except to reflect the result of the function.



Issue 0331: permit FE_DIVBYZERO when errno says EDOM

Authors: P. J. Plauger, J11
Date: 2006-08-01
Reference document: N1184
Status: Closed
Converted from: summary-c99.htm, dr_331.htm

Summary

Regarding 7.12.1 para 2,

which says that if both errno and fp exceptions are used, and if a domain error occurs, then errno gets EDOM and the fp exception is FP_INVALID:

The purpose of this document is to initiate a formal potential defect report to request that FE_DIVBYZERO can also be acceptable here.
My previous emails contained a substantive typo which may have created unnecessary confusions.

Suggested Technical Corrigendum


Comment from WG14 on 2007-10-10:

Committee Discussion (for history only)

Fall 2006

At the fall meeting it was suggested that there need not be a change to 7.12.1. No consensus was reached, leave in open status.

Spring 2007

In London the consensus was that no change is required.

Proposed Committee Response

The Standard seems clear, no change is needed.



Issue 0332: gets is generally unsafe

Authors: Douglas A. Gwyn <gwyn@arl.army.mil>, Gwyn (US)
Date: 2006-10-17
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_332.htm

Summary

The gets function's notorious vulnerability to buffer overrun ought to be addressed.

Rationale

The gets function draws much criticism due to its vulnerability to buffer overrun, which is inherent in its legacy interface specification. Its very presence in the Standard has been taken by many as evidence of WG14's ineptitude or lack of concern for software reliability, despite arguments to the contrary. The Committee may be more favorably regarded within the programming community if it takes reasonable steps to address this issue.

The recent publication of TR 24731, which specifies an alternative function gets_s that could be used instead of gets, does not satisfy the critics who claim that the continuing existence of the gets specification in the C standard amounts to an endorsement of its unsafe use in new programs.

Discussion

Consider this representative usage of gets:

#include <stdio.h>
static char line[BUFSIZ];     /* BUFSIZ is bigger than any normal text line */
extern void process(char *);
int main(void) {
    while (gets(line))
        process(line);        /* may invoke puts(line), etc. */
    return 0;
}

This shows how convenient the gets interface is. The well-known problem with this interface occurs when the standard input stream contains a text line longer than the allocated size of the buffer; because gets has no way to know that size, it blindly continues to store data beyond the end of the array, with potentially devastating impact on program operation. The infamous 1988 Morris Internet worm was merely the first of many attacks that exploit this behavior to breach security in network applications.

What might be done to improve the specification for gets so that the safety of this exceptionally convenient interface can be assured? (I do not recommend removing it altogether!) It seems evident that the only feasible change would be to impose a limit on the amount of data transferred. Requiring the programmer to establish the limit through some additional interface would sacrifice the convenience. The alternative is to impose some constant limit, in which case the remaining question is what would be a suitable constant. That can be answered by examining existing uses of gets to determine typical buffer sizes. It appears that two usage patterns predominate: Using the BUFSIZ macro which happens to be conveniently at hand as a consequence of #include <stdio.h>, or using some assumed text-line length such as 80.

Restricting the amount of data transferred to only 80 characters may be too severe for many applications, and in any case it would necessitate the introduction of a new limit macro such as LINE_MAX to provide a convenient way for programmers to declare suitable buffer arrays. Therefore I recommend instead that the existing usage of BUFSIZ be legitimatized, as follows.

Suggested Technical Corrigendum

Add the following sentence to the Description in subclause 7.19.7.7 (The gets function)], between the two existing sentences:

At most BUFSIZ-1 characters are copied to the array; excessive characters are discarded.

(The portion after the semicolon isn't strictly necessary, but it adds clarity.)

Impact

The proposed change to the gets specification would have the effect of preventing buffer overruns in many existing applications. Overly long input lines would be silently truncated (which is better than the alternative of treating them as multiple lines).

Existing applications using small buffers would not be automatically rescued by this change; however, there would be a simple source-code fix (change the buffer size). New applications would obtain safe behavior by using the known limit for buffer allocation, exactly as in the above example.

Adoption of such a change would demonstrate the committee's willingness to improve specifications compatibly with the existing standard, without resorting to unnecessarily drastic measures.


Comment from WG14 on 2007-09-06:

Committee Discussion (for history only)

The Committee thinks that the programming community would be better served by flagging the gets() function as deprecated.

Technical Corrigendum

Add to subclause 7.26.9:

The gets function is obsolescent, and is deprecated.

Add forward reference in 7.19.7.7 to 7.26.9



Issue 0333: Missing Predefined Macro Name

Authors: Austin Group, Nick Stoughton (US)
Date: 2006-10-24
Reference document: DR_321,
Status: Fixed
Fixed in: C99 TC3
Cross-references: 0321
Converted from: summary-c99.htm, dr_333.htm

Summary

Defect report DR_321 introduced a new pre-defined macro name, __STDC_MB_MIGHT_NEQ_WC__ that is conditionally defined by the implementation. However, this new macro is not in the list of macros that may be conditionally defined by the implementation in 6.10.8, para 2.

Suggested Technical Corrigendum

Add, in proper alphabetic order in the list in 6.10.8 para 2:

__STDC_MB_MIGHT_NEQ_WC__ The integer constant 1, intended to indicate that there might be some character x in the basic character set, such that 'x' need not be equal to L'x'.


Comment from WG14 on 2007-09-06:

Technical Corrigendum

Add, in proper alphabetic order in the list in 6.10.8 paragraph 2:

__STDC_MB_MIGHT_NEQ_WC__ The integer constant 1, intended to indicate that, in the encoding for wchar_t, a member of the basic character set need not have a code value equal to its value when used as the lone character in an integer character constant.



Issue 0334: Missing semantics of comparison macros

Authors: WG 14, Fred Tydeman (USA)
Date: 2006-12-12
Reference document: ISO/IEC WG14 N1203
Status: Closed
Converted from: summary-c99.htm, dr_334.htm

Summary

Section 7.12.14 Comparison macros (and subsections) are missing Semantics. In particular, something along the lines of: "The usual arithmetic conversions are performed on the operands." This matters if the two operands are of different type, e.g., isless(4.f/3.f,4.L/3.L).

In addition, we might need to add something alone the lines of: "The result of the ... operator is ..." to each of the subsections. We should consider section 6.5.8 Relational operators when we process this defect.

We should review the Constraints of 6.5.* and consider adding something along the lines of: "Each of the operands shall have real floating-type." to 7.12.14 as a constraint. The example in 7.12.3.1 paragraph 4 which uses sizeof will not work when float and _Decimal32 are the same size; nor for double and _Decimal64 being the same size.

Suggested Technical Corrigendum


Comment from WG14 on 2008-04-16:

Proposed Technical Corrigendum

Committee Discussion (for history only)

Spring 2007

There seem to be consensus that the comparison functions are under-specified.

The Standard currently says:

In the synopses in this subclause, real-floating indicates that the argument shall be an expression of real floating type.

This is well defined, see 6.2.5 para 10. However, several in attendance believe there should be explicit language explaining whether or not the two arguments to a comparison macro must be the same real-floating type or allowed to be different real-floating type.

Fall 2007

It as also asked for the following to be added to the committee discussion:

IEEE-754 (and IEEE-754R) require that comparison operations work in all supported formats, even if the operands' format differ. C99+TC1+TC2, Annex F.3, printed page 445, first bullet says that the comparison macros (along with the relational and equality operators) are the IEC 60559 comparisons.

Spring 2008

This work could possibly fit into the type generic/overloading project that needs to be completed for C1X.

Committee Response

This issue will be addressed in a future revision of the C standard. See WG 14 document Nxxx.



Issue 0335: _Bool bit-fields

Authors: WG 14, Fred Tydeman (USA)
Date: 2006-12-12
Reference document: ISO/IEC WG14 N1204, ISO/IEC WG14 DR 262, ISO/IEC WG14 DR 315
Status: Closed
Cross-references: 0262, 0315
Converted from: summary-c99.htm, dr_335.htm

Summary

What are the constraints on and semantics of _Bool bit-fields?

  #include <stdbool.h>
  struct bits {
      _Bool    bbf1 : 1;        /* unsigned 1-bit _Bool bit-field */
      _Bool    bbf3 : 3;        /* unsigned 3-bit _Bool bit-field */
  } bits;
  int main(void){
    bits.bbf1 = true;              /* the value 1u */
    bits.bbf1 = ~ bits.bbf1;       /* undefined? 0u? 1u? */
    bits.bbf3 = true;              /* the value 1u */
    bits.bbf3 = ~ bits.bbf3;       /* undefined? 0u? 1u? 6u? */
    return 0;
  }

What is the maximum width of a _Bool bit-field allowed that does not cause a constraint violation? 1? CHAR_BIT? Something else? Is bbf3 a constraint violation?

DR 262 changed 6.7.2.1#3 to require a constraint violation if a bit-field width is too large.

6.2.5#2 says _Bool can hold the values 0 and 1.

6.2.6.2#6 discusses width.

I see nothing that says the width of a _Bool is 1.

6.7.2.1#9 has: If the value 0 or 1 is stored into a nonzero-width bit-field of type _Bool, the value of the bit-field shall compare equal to the value stored.

So, if a value other than 0 or 1 is stored into a nonzero-width bit-field of type _Bool, is that undefined?

The first assignment gives the bit-field the value 1u. The ~ of that value yields ...1111110u. When that value is then stored into the _Bool bit-field, what value is stored?

6.3.1.2 Boolean type has: When any scalar value is converted to _Bool, the result is 0 if the value compares equal to 0; otherwise, the result is 1.

6.7.2.1#9 has: A bit-field is interpreted as a signed or unsigned integer type consisting of the specified number of bits.

So, does a _Bool bit-field have the semantics of a _Bool (as per 6.3.1.2) or of an unsigned integer type (as per 6.7.2.1)? DR 315 might be relevant.

Suggested Technical Corrigendum


Comment from WG14 on 2008-07-21:

Proposed Technical Corrigendum

Committee Discussion (for history only)

Spring 2007

The width of a _Bool bit-field is at most the implementation defined width of the type _Bool. A _Bool bit-field has the semantics of a _Bool (and not an unsigned int).

Spring 2008

6.7.2.1 paragraph 3 covers the above Committee discussion. (9899:1999 + TC1 + TC 2 + TC3)

The expression that specifies the width of a bit-field shall be an integer constant expression with a nonnegative value that does not exceed the width of an object of the type that would be specified were the colon and expression omitted.

Therefore the width of a _Bool bit-field is at most the implementation-defined width of the type _Bool.

Committee Response

6.2.5 paragraph 6 states that

The type _Bool and the unsigned integer types that correspond to the standard signed integer types are the standard unsigned integer types.

In other words, _Bool is one of the unsigned integer types whether it is used in a bit-field or not. 6.3.1.2p1 explicitly defines the semantics of _Bool, which are different from other unsigned integer types.

A _Bool bit-field has the semantics of a _Bool (and not unsigned int).

6.7.2.1 paragraph 3 (9899:1999 + TC1 + TC 2 + TC3) states that

The expression that specifies the width of a bit-field shall be an integer constant expression with a nonnegative value that does not exceed the width of an object of the type that would be specified were the colon and expression omitted.

The width of a _Bool bit-field is at most the implementation-defined width of the type _Bool.



Issue 0336: TMP_MAX

Authors: The Austin Group, Stoughton (US)
Date: 2007-02-01
Reference document: 2004:XBD ERN 83
Status: Fixed
Fixed in: C11
Converted from: summary-c99.htm, dr_336.htm

Summary: What does TMP_MAX actually indicate?

This is a potential defect forwarded from the Austin Group.

There is a conflict between POSIX.1 and C99 over the description of TMP_MAX. POSIX.1 describes it as:

"Minimum number of unique filenames generated by tmpnam(). Maximum number of times an application can call tmpnam() reliably."

C99 (17.19.1, para 3) says it is

"the maximum number of unique file names that can be generated by the tmpnam function".

That is to say, for POSIX, it is not an error for tmpnam() to not fail when called TMP_MAX+1 times, while it is implied by the C standard that it must fail.

POSIX goes on to state:

"If tmpnam()is called more than {TMP_MAX} times, the behavior is implementation-defined."

It should also be noted that the tmpfile function (7.19.4.3) also uses TMP_MAX, but as a minimum maximum:

"It should be possible to open at least TMP_MAX temporary files during the lifetime of the program (this limit may be shared with tmpnam)"

Suggested Technical Corrigendum

Change 7.19.1 para 3 from:

the maximum number of unique file names that can be generated by the tmpnam function".

to:

the minimum number of unique file names that can be generated by the tmpnam function".

Also, at 7.19.4.4 p2, change

"The function is potentially capable of generating TMP_MAX different strings, but any or all of them may already be in use by existing files and thus not be suitable return values."

to

"The function is potentially capable of generating at least TMP_MAX different strings, but any or all of them may already be in use by existing files and thus not be suitable return values. It is implementation defined if tmpnam can generate more than TMP_MAX different strings."


Comment from WG14 on 2007-10-10:

Committee Discussion (for history only)

Proposed Technical Corrigendum

Change 7.19.1 para 3 from:

the maximum number of unique file names that can be generated by the tmpnam function".

to:

the minimum number of unique file names that can be generated by the tmpnam function".

Also, at 7.19.4.4 p2, change

"The function is potentially capable of generating TMP_MAX different strings, but any or all of them may already be in use by existing files and thus not be suitable return values."

to

"The function is potentially capable of generating at least TMP_MAX different strings, but any or all of them may already be in use by existing files and thus not be suitable return values."



Issue 0337: stdio.h macro definition problems

Authors: Austin Group, Nick Stoughton (US)
Date: 2007-02-28
Status: Closed
Converted from: summary-c99.htm, dr_337.htm

Summary

The BUFSIZ macro is introduced in 7.19.1 para 3 as

BUFSIZ
which expands to an integer constant expression that is the size of the buffer used by the setbuf function

There is no requirement that BUFSIZ should be a non-zero, positive integer constant expression. Such a requirement should be spelled out clearly.

The same is true for FOPEN_MAX and FILENAME_MAX.

Suggested Technical Corrigendum

Change the definition of BUFSIZ to:

BUFSIZ
which expands to a non-zero, positive integer constant expression that is the size of the buffer used by the setbuf function

Similarly,

FOPEN_MAX
which expands to a non-zero, positive integer constant expression that is the minimum number of files that the implementation guarantees can be open simultaneously;

FILENAME_MAX
which expands to a non-zero, positive integer constant expression that is the size needed for an array of char large enough to hold the longest file name string that the implementation guarantees can be opened;


Comment from WG14 on 2007-10-30:

Committee discussion

Spring 2007

FOPEN_MAX is required to be at least 8, see 7.19.3 paragraph 13. So FOPEN_MAX does not require any additional words.

BUFSIZ likewise must be at least 256, see 7.19.2 paragraph 7.

FILENAME_MAX 7.19.1 paragraph 3 requires that FILENAME_MAX must be at least 1.

Proposed Committee Response

All of these constants already have required minimum values that are positive, non-zero. No changes are required.



Issue 0338: C99 seems to exclude indeterminate value from being an uninitialized register

Authors: Rich Peterson <Rich.Peterson@hp.com>, Rich Peterson (US)
Date: 2007-03-09
Reference document: WG14 N1124
Status: Fixed
Fixed in: C11
Converted from: summary-c99.htm, dr_338.htm

Summary

The following function has undefined behavior under C90, but appears to be
strictly conforming under C99:

  int foo(void) {
      unsigned char uc;
      return uc + 1 >= 0;
  }

If that is true, then a C99 compiler for a real-life architecture like ia64
that supports trap representations in hardware (via NaT values) cannot in
general just allocate auto variables to registers and leave initialization
to the source code as it would for most other architectures. Instead it
would either have to initialize the register or allocate the variable to
memory. This is because ia64 NaT values only exist in register representations,
not in memory representations.

Rationale

In C90, 3.16 defines undefined behavior as "behavior, upon use of a
non-portable or erroneous program construct, of erroneous data, or of
indeterminately valued objects, for which the standard imposes no
requirements...". And 6.5.7 says: "If an object that has automatic storage
duration is not initialized explicitly, its value is indeterminate." So it
directly follows that the above function has undefined behavior under C90.

C99 then added a definition for indeterminate value (3.17.2): "either an
unspecified value or a trap representation". The first problem is that the
type unsigned char specifically is excluded from having any trap
representations. This would seem to render non-conforming a NaT
consumption fault when evaluating uc + 1 in the example function.
Furthermore, my reading of 6.2.6.2 "Integer types" is that in order for
any type to have trap representations, there must be padding bits in the
in-memory representation of the type. This is because there does not
appear to be any allowance for padding bits that are present only in the
register representation of a type, but not in memory.

Since ia64 NaT values clearly exhibit the properties intended for C99
trap representations, offering one of the few hardware implementations
of those properties, it seems most likely that either my reading is
faulty, or that the words do not correctly express the intent. I
believe the intent of excluding type unsigned char from having trap
representations was to allow it to be used to copy (via memcpy)
arbitrary memory, in the case that memory might contain trap
representations for some types. I believe it was not the intent to
require translators to perform run-time initialization of uninitialized
auto objects of type unsigned char in order to suppress hardware
detection of programming faults. And I believe it certainly was not the
intent to require that all trap representations for any type be
representable in memory, forbidding register-only trap representations
like NaT values.

Unless someone can find text that supports register-only trap
representations, I think this deserves a TC.

Suggested Technical Corrigendum

Page 6, 3.17.2, change the definition of "indeterminate value"

Old:
either an unspecified value or a trap representation

New:
either an unspecified value or a trap representation; or in
the case of an object of automatic storage duration whose address
is never taken, a value that behaves as if it were a trap
representation, even for types that have no trap representations
in memory (including type unsigned char)


Comment from WG14 on 2008-09-12:

Committee Discussion (for history only)

Spring 2007

On some hardware (e.g. Itanium), an 8-bit value may have as many as 257 different values (0-255 and a "Not a Thing" value). However, c99 explicitly forbids such a value for an unsigned char.

Page 6, 3.17.2, change the definition of indeterminate value to:

either an unspecified value or a trap representation; or in the case of an object of automatic storage duration whose address is never taken, a value that behaves as if it were a trap representation.

5.1.2.3 para 5 second bullet speaks to this also.

Fall 2007

See WG14 e-mail SC22WG14.11380

While some agreed with the comments in this email others did not.

Spring 2008

Regarding WG14 e-mail SC22WG14.11380, the observations about trap representations are correct, and it is unfortunate that the DR was written in a way that relied on trap representation terminology and behavior. In fact, the problem and solution are not really related to trap representation as defined in the standard at all.

A better way to describe the issue might be to talk about use of an uninitialized object that is eligible to have register storage class (i.e. an object of automatic storage duration whose address is never taken).

Also the original DR's suggested wording change was made in the definition of indeterminate value. The reason for that was to trigger undefined behavior, which would have worked in C90, but in C99 the definition of undefined behavior was changed such that it does not mention indeterminate value.

Change for C1X:

6.3.2.1 paragraph 2, add a sentence to the end:

If the lvalue designates an object of automatic storage duration that could have been declared with register storage class (never had its address taken), and that object is uninitialized (not declared with an initializer, and no assignment to it has been performed prior to the use), the behavior is undefined.



Issue 0339: Variably modified compound literals

Authors: Joseph Myers <joseph@codesourcery.com>, Joseph Myers (UK)
Date: 2007-03-24
Reference document: ISO/IEC WG14 N1120
Status: Fixed
Fixed in: C11
Cross-references: 0328
Converted from: summary-c99.htm, dr_339.htm

Summary

Consider the code:

    extern int a;
    void *p = &(int (*)[a]){ 0 };

Does such a variably modified compound literal at file scope violate any constraint? 6.7.5.2#2 says:

[#2] Only an ordinary identifier (as defined in 6.2.3) with both block scope or function prototype scope and no linkage shall have a variably modified type. If an identifier is declared to be an object with static storage duration, it shall not have a variable length array type.

However, this only seems to constrain declarations of identifiers, not any other expression with variably modified type (such as a compound literal, inside or outside a function). If however the above code is valid, when is a evaluated for the purposes of the requirement in 6.7.5.2#5 that "each time it is evaluated it shall have a value greater than zero"? Must a have positive value throughout execution of the program, or is it only the initial value of a which must be positive? (I think the initializer is a constant expression, being the address of an object of static storage duration.)

The variably modified compound literal is an object, and I think it should be treated like other objects outside functions and required not to have variably modified type (even if inside sizeof, just like the initializers of compound literals outside functions must be constant even if inside sizeof).

Suggested Technical Corrigendum

6.5.2.5 paragraph 3, after "shall consist of constant expressions" add "and the type name shall not specify a variably modified type".


Comment from WG14 on 2008-07-21:

Committee Discussion

Paragraph in question (paragraph 3 of 6.5.2.5) has been changed by DR 328.

The suggested Technical Corrigendum looks appropriate, however, it could be redundant.

Committee Response

This defect report is answered by DR 328.

Constraints and Semantics are the same as 6.7.8 Initialization



Issue 0340: Composite types for variable-length arrays

Authors: Joseph Myers <joseph@codesourcery.com>, Joseph Myers (UK)
Date: 2007-03-24
Reference document: ISO/IEC WG14 N1221
Status: Fixed
Fixed in: C11
Cross-references: 0342
Converted from: summary-c99.htm, dr_340.htm

Summary

The definition of composite types in 6.2.7#3 says "If one type is an array of known constant size, the composite type is an array of that size; otherwise, if one type is a variable length array, the composite type is that type." and also "These rules apply recursively to the types from which the two types are derived.". Which of these wins for variable length array types? Are the element types composed recursively, or is the element type of the variable length array type taken even though it may have less information than the other element type? (That loss of information in the composite type would mean some sequences of three or more declarations of the same function are constraint violations for some orderings of the declarations and undefined behavior for other orderings.)

See reflector messages 11145-11147 for discussion.

Suggested Technical Corrigendum

6.2.7 paragraph 3, change "is that type" to "is an array of that size; in either case, the element type of the composite type is the composite type of the two element types".


Comment from WG14 on 2008-09-10:

Committee Discussion

The element types are composed. Suggested TC is close, but not quite right. The example from 11145 should be included here.

Also see N1238 and WG14 e-mail SC22WG14.11145.

Fall 2007

No consensus was reached on the words from N1238.

Spring 2008

It appears that the current implementations differ in this area. Some compilers works one way (as described), while others do not. Probably best solution is to make this undefined behavior.

Proposed Technical Corrigendum

In subclause 6.2.7, paragraph 3, change the first bullet to the following.

– If both types are array types, the following rules are applied:

If one type is an array of known constant size, the composite type is an array of that size.
Otherwise, if one type is a variable length array whose size is specified by an expression that is not evaluated, the behavior is undefined.
Otherwise, if one type is a variable length array whose size is specified, the composite type is a variable length array of that size.
Otherwise, if one type is a variable length array of unspecified size, the composite type is a variable length array of unspecified size.
Otherwise, both types are arrays of unknown size, and the composite type is an array of unknown size.
The element type of the composite type is the composite type of the two element types.

In subclause J.2, paragraph 1, insert the following bullet in order.

– A program requires the formation of a composite type from a variable length array type whose size is specified by an expression that is not evaluated (6.2.7).



Issue 0341: [*] in abstract declarators

Authors: Joseph Myers <joseph@codesourcery.com>, Joseph Myers (UK)
Date: 2007-03-24
Reference document: ISO/IEC WG14 N1222
Status: Fixed
Fixed in: C11
Converted from: summary-c99.htm, dr_341.htm

Summary

6.7.5.2#4 says that * as an array size "can only be used in declarations with function prototype scope", and paragraph 5 says "If the size is an expression that is not an integer constant expression: if it occurs in a declaration at function prototype scope, it is treated as if it were replaced by *".

But is a type name in a function prototype a declaration, and does it have function prototype scope? Scopes are only defined in 6.2.1 for identifiers, and such type names do not declare identifiers. The presence of [*] in the syntax for abstract declarators suggests that

    void f(int (*)[*]);

was intended to be valid and void f(int (*)[a]); was intended to be equivalent to it, but there are no declarations at function prototype scope involved.

Similarly, what is "in" such a declaration? Is the following valid?

    void f(int (*)[sizeof(int (*)[*])]);

Although the [*] lies within a parameter declaration, it's within an expression inside it; not one of the declarators involved in declaring the identifier with function prototype scope.

Suggested Technical Corrigendum

6.7.5.2 paragraph 4, change "declarations with function prototype scope" to "the nested sequence of declarators or abstract declarators for a function parameter in a function declaration that is not a definition"; remove the footnote. Paragraph 5, change "declaration at function prototype scope" to "the nested sequence of declarators or abstract declarators for a function parameter in a function declaration that is not a definition".


Comment from WG14 on 2008-07-21:

Committee Discussion

Spring 2007

There was consensus that the first example should be valid, and the second should be invalid.

Also see N1238.

Fall 2007

Above reference to N1238 is not relevant.

It appears the issue hinges entirely on the point that a type-name is not a declaration and does not declare an identifier, and because of that it has no scope. Instead of adding complex wording to avoid using the term "scope" as suggested in the DR, it seems clearer to modify the definition of Scope such that it applies to type-name, which is described in 6.7.6 as "syntactically a declaration for a function or an object of that type that omits the identifier".

Spring 2008

The Committee does not see a way to avoid this change, it seems to be safe. Not altogether satisfied with the aesthetics of this change, but this seems to be a satisfactory way forward.

Technical Corrigendum

6.2.1, add a new paragraph at the end (following paragraph 7):

As a special case, a type-name (which is not a declaration of an identifier) is considered to have a scope that begins just after the place within the type-name where the omitted identifier would appear were it not omitted.

Also add a forward reference to Type names (6.7.6).

6.7.5.2 paragraph 4, change

declarations with function prototype scope

to

declarations or type-names with function prototype scope



Issue 0342: VLAs and conditional expressions

Authors: Joseph Myers <joseph@codesourcery.com>, Joseph Myers (UK)
Date: 2007-03-24
Reference document: ISO/IEC WG14 N1223
Status: Fixed
Fixed in: C11
Cross-references: 0340
Converted from: summary-c99.htm, dr_342.htm

Summary

Consider the code:

    int a, b;
    void *p1(void), *p2(void);
    int c1(void);
    int d1(void);
    int z1(void), z2(void);

    int
    h(void)
    {
      int r = (c1()
               ? (z1(), (int (*)[d1()])p1())
               : (z2(), (int (*)[])p2()))[a][b];
      return r;
    }

The type of the conditional expression involves the size expression d1() that's only evaluated in one part of the expression, and this information is needed to evaluate the array reference even when c1() returns false.

For a more complicated example and discussion see reflector messages 10731-10754. The validity of that more complicated example depends on the interpretation of composite type rules as in DR 340, so this example has been simplified to avoid that problem.

Suggested Technical Corrigendum

6.7.5.2 paragraph 6 at end add "or one of the size specifiers (including the case of a single size specifier where the other array type does not include a size specifier) is not an integer constant expression and is not evaluated during the flow of execution." with a footnote "This case arises where a conditional expression involves a cast to variably modified type or a compound literal of variably modified type."


Comment from WG14 on 2008-09-10:

Committee Discussion (for history only)

Spring 2008

The consensus is that the Note in the previous version of this DR was not accurate and should be removed. The DR should be in Review status

Fall 2008

The consensus at this meeting is that this defect should be linked with defect report 340.

Proposed Committee Response

See defect report 340



Issue 0343: Initializing qualified wchar_t arrays

Authors: Joseph Myers <joseph@codesourcery.com>, Joseph Myers (UK)
Date: 2007-03-24
Reference document: ISO/IEC WG14 N1224
Status: Fixed
Fixed in: C11
Converted from: summary-c99.htm, dr_343.htm

Summary

6.7.8 paragraph 15 says:

[#15] An array with element type compatible with wchar_t may be initialized by a wide string literal, optionally enclosed in braces. [...]

What of arrays with element type a qualified version of wchar_t? Is

    #include <stddef.h>
    const wchar_t x[] = L"foo";

valid? Surely it must be intended to be, but the type const wchar_t isn't compatible with wchar_t.

(The validity for character strings (paragraph 14) depends on "character type" including qualified character types. The definition of character types in 6.2.5 paragraph 15 does not mention qualified types. Other parts of the Standard also make more sense if "character type" is taken to include qualified character types; for example, 6.5 paragraph 7 of which the last point says "a character type" but the first four points come in matching pairs for qualified and unqualified types, and 6.3.2.3 paragraph 7.)

Suggested Technical Corrigendum

6.7.8 paragraph 15, change "wchar_t" to "a qualified or unqualified version of wchar_t".


Comment from WG14 on 2007-09-07:

Proposed Technical Corrigendum

Change 6.7.8 paragraph 15:

"wchar_t"

to

"a qualified or unqualified version of wchar_t".



Issue 0344: Casts in preprocessor conditional expressions

Authors: WG21, Clark Nelson
Date: 2007-04-23
Status: Fixed
Fixed in: C11
Converted from: summary-c99.htm, dr_344.htm

Summary

6.10.1 paragraph 1 states:

The expression that controls conditional inclusion shall be an integral constant expression except that: it shall not contain a cast; ...

The prohibition of casts is vacuous, as pointed out in the footnote in that paragraph:

Because the controlling constant expression is evaluated during translation phase 4, all identifiers either are or are not macro names — there simply are no keywords, enumeration constants, and so on.

As a result, there can be no casts, which require either keywords or identifiers that resolve to types in order to be recognized as casts.

The prohibition of casts is also misleading: the presence of a "shall not" in a "Constraints" paragraph suggests that an implementation is required to diagnose this condition. However, in an example like this:

#if (int)+0

There is a construct which appears to be a cast, but is not, and is syntactically and semantically valid.

Suggested Technical Corrigendum

Change 6.10.1p1:

The expression that controls conditional inclusion shall be an integer constant expression except that: it shall not contain a cast; identifiers (including those lexically identical to keywords) are interpreted as described below;141) and it may contain unary operator expressions of the form


Comment from WG14 on 2007-07-21:

Technical Corrigendum

Change 6.10.1p1:

The expression that controls conditional inclusion shall be an integer constant expression except that: it shall not contain a cast; identifiers (including those lexically identical to keywords) are interpreted as described below;141) and it may contain unary operator expressions of the form



Issue 0345: Where does parameter scope start?

Authors: Rob Arthan <UK>, Derek Jones (UK)
Date: 2007-04-23
Status: Fixed
Fixed in: C11
Converted from: summary-c99.htm, dr_345.htm

Summary

1)

The wording in 6.2.1p7:

Any other identifier [except a struct/union tag or an enumeration constant] has scope that begins just after the completion of its declarator.

permits the use of q in the following declaration of the parameter r.

void f(
     long double q,
     char (**r)[10 * sizeof q])
{ }

However, consider 6.9.1p9 (which was not in C90):

Each parameter has automatic storage duration. Its identifier is an lvalue, which is in effect declared at the head of the compound statement that constitutes the function body ...

This does not appear to permit the use of q in the declaration of the parameter r.

Does q have two points of declaration (one at the end of its declarator and one at the head of the compound statement)?

2)

Consider the situation when a function has a parameter with the same name as the function, as in the following example:

#include>stdio.h<
void f(
     long double f,
/* #1 */
     char (**a)[10 * sizeof f])
{
/* #2 */
         printf("%d\n", (int) sizeof **a);
/* #3 */
}
int main(void)
{
         f(0, 0);
         return 0;
}
/* #4 */

6.2.1p4 says:

... If an identifier designates two different entities in the same name space, the scopes might overlap. If so, the scope of one entity (the inner scope) will be a strict subset of the scope of the other entity (the outer scope). Within the inner scope, the identifier designates the entity declared in the inner scope ...

The scope of the function f starts at #2 and continues to the end of the file (#4). The scope of the parameter f starts at #1 and continues to the end of the definition of the function f (#3). Neither of these scopes is a strict subset of the other.

Suggested Technical Corrigendum

1)

None proposed.

2)

One solution is to fix up the scope overlap wording in 6.2.1p4 and acknowledge that the function f in the above example is not callable (although currently callable by some compilers that have been tried).

The second sentence from 6.2.1p4 could be amended to read:

... scopes might overlap. If so, the scope of one entity (the inner scope) will end strictly before the scope of the other entity (the outer scope). Within the inner scope, ...

So the example would be conformant and would print out 10 times the size of a long double.


Comment from WG14 on 2008-09-12:

Committee Discussion

Spring 2007

There was no consensus for question 2.

For question 1: The Committee believes that 6.9.1 paragraph 9 is a comment on the storage duration and does not override the lexical scope described in 6.2.1 paragraph 7.

Fall 2007

General consensus is that the wording in the Standard is basically not correct and needs to be reworked.

Also see comments in WG14 e-mail SC22WG14.11380

Spring 2008

Question 1

C++ 3.3.2p2 has three sentences (words irrelevant to C are deleted):

  1. The potential scope of a function parameter name or of a function-local predefined variable in a function definition begins at its point of declaration.
  2. The potential scope of a parameter or of a function-local predefined variable ends at the end of the outermost block of the function definition.
  3. A parameter name shall not be redeclared in the outermost block of the function definition.

For sentence 1, 6.2.1p7 already says:

Any other identifier has scope that begins just after the completion of its declarator.

For sentence 2, 6.2.1p4 already says:

If the declarator or type specifier that declares the identifier appears inside a block or within the list of parameter declarations in a function definition, the identifier has block scope, which terminates at the end of the associated block.

For sentence 3, 6.7p3 already says:

If an identifier has no linkage, there shall be no more than one declaration of the identifier (in a declarator or type specifier) with the same scope and in the same name space, except for tags as specified in 6.7.2.3.

And 6.2.1p6 says:

Two identifiers have the same scope if and only if their scopes terminate at the same point.

So what the C++ standard says, and what the C standard needs to say, about the scope of a parameter name is already covered in the C standard, outside of 6.9.1p9. Therefore, I suggest modifying 6.9.1p9 as indicated:

Each parameter has automatic storage duration. Its identifier is an lvalue, which is in effect declared at the head of the compound statement that constitutes the function body (and therefore cannot be redeclared in the function body except in an enclosed block). The layout of the storage for parameters is unspecified.

Additionally, if desired, add a footnote at the point of the deletion:

A parameter identifier cannot be redeclared in the function body except in an enclosed block.

Question 2

The words "a strict subset" are technically incorrect, but nothing really depends on them. Fixing them can be treated as an editorial matter.

One possibility would be simply to qualify that statement with "generally" or "usually". The submitter's suggested technical corrigendum would also be technically correct. In 6.2.1p4:

... If an identifier designates two different entities in the same name space, the scopes might overlap. If so, the scope of one entity (the inner scope) will be a strict subset of end strictly before the scope of the other entity (the outer scope). Within the inner scope, the identifier designates the entity declared in the inner scope; the entity declared in the outer scope is hidden (and not visible) within the inner scope.

Change for C1X

Change 6.9.1 paragraph 9 to:

Each parameter has automatic storage duration. Its identifier is an lvalue,* the layout of the storage for parameters is unspecified.

*A parameter identifier cannot be redeclared in the function body except in an enclosed block.

Change 6.2.1 paragraph 4 to:

... If an identifier designates two different entities in the same name space, the scopes might overlap. If so, the scope of one entity (the inner scope) will end strictly before the scope of the other entity (the outer scope). Within the inner scope, the identifier designates the entity declared in the inner scope; the entity declared in the outer scope is hidden (and not visible) within the inner scope.