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 INT N_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 |
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
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.
Append a new paragraph to 7.18.3:
The value of
SIZE_MAX
shall be no greater than that ofULONG_MAX
. The absolute values ofPTRDIFF_MIN
andPTRDIFF_MAX
shall be no greater than those ofLONG_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 ofptrdiff_t
shall be no greater than that ofsigned long
);size_t
which is the unsigned integer type of the result of the
sizeof
operator (the width ofsize_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:
- the original value was taken from an object whose type is derived from a typedef defined in a header provided by the implementation;
- that type has a conversion rank greater than that of signed long;
- the result type has a conversion rank equal to that of signed long.
(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:
There is no consensus to make this change or any change along this line.
<fenv.h>
functionsAuthors: 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
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:
- 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".- 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:
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
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
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.
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:
Changes were incorporated into the Standard just before printing. This was considered an editorial change by the Committee.
size_t
and ptrdiff_t
as a long long
typeAuthors: 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
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.
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:
Add to the end of 7.17:
Recommended Practice
[#4] The types used for
size_t
andptrdiff_t
should not have an integer conversion rank greater than that ofsigned long
unless the implementation supports objects large enough to make this necessary.
__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
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.
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_least
assignment-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:
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.
Do nothing.
Remove this feature (the use of static to mean a minimum array size).
Deprecate this feature (the use of static to mean a minimum array size).
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-liststatic
assignment-expression]
to:
direct-declarator
[
type-qualifier-listoptstatic
assignment-expression]
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:
There is no consensus to make this change or any change along this line.
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
For consistency with real floating types, the type float _Complex
should be
promoted by the default argument promotions to double _Complex
.
Change 6.5.2.2p6 in part, from:
and arguments that have type
float
are promoted todouble
.
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 isdouble
.
Comment from WG14 on 2001-09-18:
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.
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
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.
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.
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).
- one type is the type of the parameter, and the other type the type of the argument, when a function is called without a prototype in scope; [*]
- one type is the type of an argument corresponding to a trailing ellipsis in a function call and the other is specified as the type argument of an invocation of the
va_arg
macro;- one type is the type of an argument to a function such as
fprintf
or the type pointed to by an argument to a function such asfscanf
, and the other is the type implied by the corresponding conversion specifier.[*] 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_Iare defined, respectively, as
_Imaginary
and a constant expression of typeconst float _Imaginary
with the value of the imaginary unit. The macroI
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:
In 6.4.1 append to paragraph 2:
The keyword
_Imaginary
is reserved for specifying imaginary types.footnotefootnoteOne possible specification for imaginary types is Annex G.
In 6.7.2 delete "_Imaginary
" from paragraph 1, delete the cases:
float _Imaginary
double _Imaginary
long double _Imaginary
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
Iexpands to
_Complex_I
.162[#4] Notwithstanding the provisions of subclause 7.1.3, a program may undefine and perhaps then redefine the macros
complex
andI
.
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_Iare defined, respectively, as
_Imaginary
and a constant expression of typeconst float _Imaginary
with the value of the imaginary unit. The macroIis 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 macroimaginary
.
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
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.
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.
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:
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.
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.
INT
N_C
macrosAuthors: 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
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
INT
N_C(
value)
shall expand to a signed integer constant with the specified value and typeint_least
N_t
.
(Similarly for UINT
N_C
.) The paragraph preceding this overly restrictive
specification reflects the actual intent:
... a type with at least the specified width.
Possible Solutions
int_least
N_t
.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:
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
INT
N_C(
value)
shall expand to an integer constant expression corresponding to the typeint_least
N_t
. The macroUINT
N_C(
value)
shall expand to an integer constant expression corresponding to the typeuint_least
N_t
. For example, ifuint_least64_t
is a name for the typeunsigned long long int
, thenUINT64_C(0x123)
might expand to the integer constant0x123ULL
.
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)
fprintf %a
and %A
conversions recommended practiceAuthors: WG 14, Fred Tydeman (US)
Date: 1999-10-20
Status: Fixed
Fixed in: C99 TC1
Converted from: summary-c99.htm, dr_210.htm
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:
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
andA
conversions, ifFLT_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
andA
conversions, ifFLT_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.
Authors: NCITS J11, Fred Tydeman (US)
Date: 1999-10-20
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_211.htm
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:
scanf
family, strtod
family)printf
family)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 fore,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.
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 andfscanf
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:
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:
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.
Authors: Clive Feather (UK)
Date: 1999-10-20
Reference document: ISO/IEC WG14 N898
Status: Closed
Converted from: summary-c99.htm, dr_212.htm
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 differentLC_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.
(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-valuedmbstate_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 unboundmbstate_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 boundmbstate_t
object is used with a different multibyte character sequence, a differentLC_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
andn
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 callwcrtomb(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 ofwc
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 insteadps
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, the
mbstate_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, andfgetwc
returnsWEOF
. [...]
Comment from WG14 on 2001-09-18:
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.
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
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:
In 7.24.6.3.2 paragraph 4, change the label of the case "positive" to "between 1
and n
inclusive".
atexit
function registrationAuthors: Clive Feather (UK)
Date: 2000-04-04
Status: Closed
Converted from: summary-c99.htm, dr_214.htm
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.
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:
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.
Authors: Clive Feather (UK)
Date: 2000-04-04
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_215.htm
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:
Paragraph 4 from 6.5.8 should be duplicated in the Semantics section of 6.5.9.
Authors: Clive Feather (UK)
Date: 2000-04-04
Status: Fixed
Fixed in: C99 TC1
Converted from: summary-c99.htm, dr_216.htm
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 ?
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:
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
anduintmax_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.
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.
asctime
limitsAuthors: Clive Feather (UK)
Date: 2000-04-04
Status: Closed
Cross-references: 0326
Converted from: summary-c99.htm, dr_217.htm
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.
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:
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.
Authors: Clive Feather (UK)
Date: 2000-04-04
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_218.htm
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.
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:
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()
.
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.
Authors: Clive Feather (UK)
Date: 2000-04-04
Status: Closed
Converted from: summary-c99.htm, dr_219.htm
6.5 reads:
[#6] [...] If a value is copied into an object having no declared type using
memcpy
ormemmove
, 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:
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
ormemmove
, 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
.
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).
Authors: Clive Feather (UK)
Date: 2000-04-04
Status: Fixed
Fixed in: C99 TC1
Converted from: summary-c99.htm, dr_220.htm
7.19.6.1[#4] 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; [...]
7.19.6.2 #3 reads in part:
- An optional nonzero decimal integer that specifies the maximum field width (in characters).
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:
- the value may be zero
- a non-significant leading zero digit may be used
- the value may be negative.
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:
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".
Authors: Clive Feather (UK)
Date: 2000-04-04
Status: Closed
Converted from: summary-c99.htm, dr_221.htm
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
(whereN
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 expressionP
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 expressionQ
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.
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
andN+(P)
, (whereN
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
andQ
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 typeptrdiff_t
. Moreover, if the expressionP
points either to an element of an array object or one past the last element of an array object, and the expressionQ
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 expressionP
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
andQ
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 typeptrdiff_t
.88)
Comment from WG14 on 2001-09-18:
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 expressionQ
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.
Authors: Clive Feather (UK)
Date: 2000-04-04
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_222.htm
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:
Comment from WG14 on 2001-09-18:
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:
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.
FP_FAST_FMAF
and FP_FAST_FMAL
should be integer constantAuthors: Bill Plauger (US)
Date: 2000-04-10
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_223.htm
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:
FP_FAST_FMAF
and FP_FAST_FMAL
should be defined as integer constant 1.
fpclassify
return is not definedAuthors: Bill Plauger (US)
Date: 2000-04-10
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_224.htm
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:
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.
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
strtod
, strtof
and strtold
expected form of the subject sequenceAuthors: Bill Plauger (US)
Date: 2000-04-10
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_225.htm
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.
In 7.20.1.3 replace:
- one of
INF
orINFINITY
, ignoring case- one of
NAN
orNAN(
n-char-sequenceopt)
, ignoring case in theNAN
part, where:
with:
- either
INF
not followed byI
, orINFINITY
, ignoring case- either
NAN
not followed by a left parenthesis, orNAN(
n-char-sequenceopt)
, ignoring case in theNAN
part, where:
Comment from WG14 on 2001-09-18:
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:
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.
strftime
referencesAuthors: Bill Plauger (US)
Date: 2000-04-10
Status: Closed
Converted from: summary-c99.htm, dr_226.htm
In <time.h>
, strftime
references 7.23.1, but the reference should be
7.23.3.1.
Comment from WG14 on 2001-09-18:
The Standard is correct, the reference should be 7.23.1.
strftime %U
, %V
, and %W
conversion specifiersAuthors: Bill Plauger (US)
Date: 2000-04-10
Status: Closed
Converted from: summary-c99.htm, dr_227.htm
In <time.h>
, strftime
conversion specifiers %U
, %W
, and %V
do not need
tm_year
.
Comment from WG14 on 2001-09-18:
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
.
wmemcmp
declaration in Annex BAuthors: Bill Plauger (US)
Date: 2000-04-10
Status: Fixed
Fixed in: C99 TC1
Converted from: summary-c99.htm, dr_228.htm
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:
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
.
localeconv() *_sep_by_space
table entries issuesAuthors: Project Editor (Larry Jones)
Date: 2000-04-10
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_229.htm
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:
In 7.11.2.1 paragraph 9:
In 7.11.2.1 paragraph 10:
n_sep_by_space
table entry for Country3 from 1
to 2
int_p_sep_by_space
table entries from 0
to 1
int_n_sep_by_space
table entries for Country1 and Country3 from 0
to 2
and for Country2 and Country3 from 0
to 1
.Authors: Derek Jones (UK)
Date: 2000-04-11
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_230.htm
Clause 6.3.1.1p2:
An enumerated type may have a rank equal to that of
int
, or even greater thanint
.
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.
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
andunsigned 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
andunsigned 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:
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.
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
andunsigned int
.
Authors: Makoto Noda (Japan)
Date: 2000-04-14
Status: Closed
Cross-references: 0448
Converted from: summary-c99.htm, dr_231.htm
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:
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.
Authors: Makoto Noda (Japan)
Date: 2000-04-14
Status: Fixed
Fixed in: C99 TC1
Converted from: summary-c99.htm, dr_232.htm
In Annex I Common warnings the text:
- A value is given to an object of an enumeration type other than by assignment of an enumeration constant that is a member of that type, or an enumeration variable that has the same type, or the value of a function that returns the same enumeration type (6.7.2.2).
the "enumeration type" should be "enumerated type".
Comment from WG14 on 2000-11-02:
Change "enumeration type" to "enumerated type".
%g
, %G
precision specificationAuthors: Chris Torek, Project Editor (Larry Jones)
Date: 2000-04-24
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_233.htm
7.19.6.1 (and similarly in 7.24.2.1):
g,G
A
double
argument representing a floating-point number is converted in stylef
ore
(or in styleF
orE
in the case of aG
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; stylee
(orE
) 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 anf
orF
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:
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:
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 stylef
ore
(or in styleF
orE
in the case of aG
conversion specifier), depending on the value converted and the precision. LetP
equal the precision if non-zero, 6 if the precision is omitted, or 1 if the precision is zero. Then, if a conversion with styleE
would have an exponent ofX
:
- if
P > X >= -4
, the conversion is with stylef
(orF
) and precisionP - (X + 1)
.- otherwise the conversion is with style
e
(orE
) and precisionP - 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.
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 macroEOF
if an input failure occurs before any conversion. Otherwise, thevscanf
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:
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
andint_n_sep_by_space
, the fourth character ofint_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)".
C
" locale collating behaviour not definedAuthors: AFNOR (Antoine Leca)
Date: 2000-10-18
Status: Closed
Converted from: summary-c99.htm, dr_235.htm
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
forstrcoll
,wcscmp
forwcscoll
, and the identity function for the latter two, but this is not presently required.
Suggested responses
There are basically two choices:
- left things as they are, since use of
strcoll
and alii in the "C
" locale is not expected to be a noteworthy situation- correct the Standard along the customary way
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 asstrcmp
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 aswcscmp
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 mostn
characters from the string pointed bys2
tos1
.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 mostn
wide characters from the string pointed bys2
tos1
.
Comment from WG14 on 2002-03-03:
The committee decided to make no change. The standard does not require that
strcoll()
and strcmp()
perform the same in the C locale.
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 causesu.md
to become undefined. If it were the case thatu.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 typeint
. 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 typedouble
.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 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;
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.
[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.
static
only count if it is on the definition?Comment from WG14 on 2003-10-23:
The Committee discussed adding a footnote to 6.7.5.3 paragraph 7 along the lines of item 1.
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.
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.fma()
overflow and underflow errors are missingAuthors: 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
The description section for
fma()
needs to mention possible overflow and underflow errors.
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()
.
In 7.12.13.1 fma
add to description:
A range error may occur.
Comment from WG14 on 2003-10-23:
In 7.12.13.1 fma
add to description:
A range error may occur.
nexttoward
description is inconsistent with 7.12.11.4. and F.9.8.3Authors: 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
The description for
nexttoward()
in Annex F should be changed to referencenextafter
to be consistent with 7.12.11.4. and F.9.8.3.
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 onnextafter
and 7.12.11.4 saysnexttoward
is similar tonextafter
. We need to make it clear thatnextafter
andnexttoward
have the same requirements with respect to range errors in annex F.
In F.9.8.4 nexttoward
change:
No additional requirements.
to
No additional requirements beyond
nextafter
.
Comment from WG14 on 2001-10-16:
In F.9.8.4 nexttoward
change:
No additional requirements.
to
No additional requirements beyond those on
nextafter
.
lrint
, llrint
, lround
, llround
, and ilogb
descriptions are not consistent for unrepresentable resultsAuthors: 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
lrint
,llrint
,lround
,llround
, andilogb
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.
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 ofilogb(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
andllrint
are inconsistent on how large arguments are treated between 7.12.9.5 (range error) and Annex F (domain error).
lround
andllround
are inconsistent on how large arguments are treated between 7.12.9.7 (range error) and Annex F (domain error).
In 7.12.6.5 ilogb
:
Change:
A range error may occur if
x
is0
.
to
A domain error occurs if
x
is0
, infinite, orNaN
.
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:
In 7.12.6.5 ilogb
:
Change:
A range error may occur if
x
is0
.
to
A domain error or range error may occur if
x
is0
, infinite, orNaN
.
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.
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
pow(0, <0)
should be considered a pole error (result is an exact infinity) in the base standard (it already is in Annex F).
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.
In 7.12.7.4 pow
:
Split:
A domain error may occur if
x
is zero andy
is less than or equal to zero.
into
A domain error may occur if
x
is zero andy
is zero.
and
A range error may occur if
x
is zero andy
is less than zero.
Comment from WG14 on 2001-10-16:
In 7.12.7.4 pow
:
Split:
A domain error may occur if
x
is zero andy
is less than or equal to zero.
into:
A domain error may occur if
x
is zero andy
is zero.
and
A domain error or range error may occur if
x
is zero andy
is less than zero.
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
logb(0)
should be considered a pole error in the base standard (it already is in Annex F).
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 aslog(0)
,log2(0)
, orlog10(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.
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:
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.
fmod()
, remainder()
, and remquo()
for a zero divisorAuthors: 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
fmod()
,remainder()
, andremquo()
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 thatfmod()
,remainder()
, andremquo()
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.
For a fixed
x
, as one takes the limit asy
approaches zero, the remainder ofx
/y
approaches zero(0 <= |result| < |y|)
and the quotient is unspecified.IEC 60559 requires that
x
REMy
, wheny
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
ory = (m+1/2)x
for integers m. We see no reason to "take the limit asy
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.
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 theremainder
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 theremquo
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 aNaN
and raises the "invalid" floating-point exception forx
infinite ory
zero.
to two items:
fmod(x,y)
returns aNaN
and raises the "invalid" floating-point exception forx
infinite.
and
For
y
zero,fmod(x,y)
either returns a zero (with sign ofx
), or returns aNaN
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 ofx
), or returns aNaN
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 ofx
), or returns aNaN
and raises the "invalid" floating-point exception; and, in both cases, has an unspecified quotient stored.
Also add,
When
remquo
returns aNaN
, the quotient stored is unspecified.
Comment from WG14 on 2001-10-16:
In 7.12.10.2 remainder
:
Add to Returns:
If
y
is zero, whether a domain error occurs or theremainder
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 theremquo
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).
tgamma(zero or negative integer)
should be considered a pole errorAuthors: 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
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.
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)
, asx
approaches -infinity, has no unique limit, so must also be considered invalid.
In 7.12.8.4 tgamma
:
Change:
A domain error occurs if
x
is a negative integer or if the result cannot be represented whenx
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 aNaN
and raises the "invalid" floating-point exception forx
a negative integer.
to
tgamma(x)
returns+INF
and raises the "divide-by-zero" floating-point exception forx
a negative integer.
Change:
tgamma(-INF)
returns aNaN
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:
In 7.12.8.4 tgamma
:
Change:
A domain error occurs if
x
is a negative integer or if the result cannot be represented whenx
is zero.
to
A domain error or range error may occur if
x
is a negative integer or zero.
Authors: WG14
Date: 2001-09-21
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_245.htm
- In F.9.8.4, the second paragraph is missing a paragraph number.
- In 7.20.7.2, the first paragraph of the Returns section is missing a paragraph number.
- In 7.18.2.1, the first paragraph is missing a paragraph number.
- In 7.18.2.2, the first paragraph is missing a paragraph number.
- In 7.18.2.3, the first paragraph is missing a paragraph number.
- In 7.18.2.4, the first paragraph is missing a paragraph number.
- In 7.18.2.5, the first paragraph is missing a paragraph number.
- In 7.19.4.3 Recommended Practice, the first paragraph is missing a paragraph number.
- In 7.21.4.3 Description, the first paragraph is missing a paragraph number.
- In G.3, the first paragraph is missing a paragraph number.
- In G.6.2.2, the first paragraph is missing a paragraph number.
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:
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
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
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.
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:
The suggested words don't appear to be an improvement; the current phrasing is clear enough.
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
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.
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:
In section 3.4.4, prepend
"Use of an unspecified value, or other ..." before "behavior where".
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
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.
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:
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.
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
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.
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:
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.
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
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.
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:
The Committee believes the Standard is correct (preprocessing directive includes non-directive), therefore, the anwser to the question on this is yes.
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.
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
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 identifieror
enum identifieroccurs 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.
Append to 6.7.2.1#6:
The keywords
struct
andunion
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
, orenum
.
Comment from WG14 on 2006-03-29:
The Committee is inclined to accept the suggested TC, but the issue is still being debated.
Append to 6.7.2.1#6:
The keywords
struct
andunion
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
, orenum
.
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
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.
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:
This should not be a constraint.
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
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 ?
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
andy
result in identical objects. Each will be an array with one element; within that element, the memberss[4]
ands[5]
are implicitly initialized to zero.
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
andy
result in identical objects. Each will be an array with one element; within that element, all the members are implicitly initialized to zero except fors[0]
. In the definition ofx
the first initializer has no effect, since the second one initializes the same subobject (x[0]
).
Comment from WG14 on 2002-05-15:
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.
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).
mbtowc
and partial charactersAuthors: Clive D.W. Feather <clive@demon.net>, UK C Panel
Date: 2001-09-07
Status: Closed
Converted from: summary-c99.htm, dr_254.htm
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.]
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. Ifs
is not a null pointer, thembtowc
function returns the first of the following that applies (given the current conversion state):
0 if s
points to the null characterbetween 1 and n
inclusiveif 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 theMB_CUR_MAX
macro.(size_t)(-2)
if the next n
bytes contribute to an incomplete (but potentially valid) multibyte character, and alln
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 macroEILSEQ
is stored inerrno
, 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:
The Committee believe the behavior of this example is unspecified. The
mbrtowc()
function provides a superior migration path, so we are leaving this
alone.
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
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:
- one promoted type is a signed integer type, the other promoted type is the corresponding unsigned integer type, and the value is representable in both types;
- both types are pointers to qualified or unqualified versions of a character type or
void
.
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.
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:
- one promoted type is a signed integer type, the other promoted type is the corresponding unsigned integer type, and the value is representable in both types;
- both types are pointers to qualified or unqualified versions of a character type or
void
.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:
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.
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
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 ofNDEBUG
(see 7.2).
Does "with no effect different" mean:
FOPEN_MAX
is defined;FOPEN_MAX
is undefined;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.
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:
The Committee believe that both answer 1 and 2 are allowed, and does not see a compelling reason to change this.
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
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.
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.
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.
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
- compatible types (and, for bit-fields, the same widths)
- signed and unsigned versions of the same integer type
- qualified or unqualified versions of matching types, or
- pointers to matching types.
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:
The current rules are the result of extensive previous deliberations. The Committee does not see a defect here.
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
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 tokendefined
is generated as a result of this replacement process or use of thedefined
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.
Change 6.10.1#1 to read:
[...]
defined identifieror
defined ( identifier )which are replaced by the token
1
if the identifier is currently
[...]
subject identifier), or the token0
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 tokendefined
appears in the list after the replacement process, or the use of thedefined
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:
The standard does not clearly specify what happens in this case, so portable programs should not use these sorts of constructs.
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
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.
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:
The standard is clear enough, and no change is needed.
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
This is an intermingling of something that started out as two separate questions:
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.
p
could point anywhere.p
at point X, and p
, q
, and r
at point Z, can all change their value.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.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:
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.
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.
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
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.
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.
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 operatorsThis 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"
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:
- they contain a comma operator (forbidden by 6.6#3)
- there is a valid interpretation of the code that uses a non-constant expression.
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 arrayIn general, the interpretation of an expression for constantness is context sensitive. For any expression which contains only constants:
- If the syntax or context only permits a constant expression, the constraints of 6.6#3 and 6.6#4 shall apply.
- Otherwise, if the expression meets the requirements of 6.6 (including any form accepted in accordance with 6.6#10), it is a constant expression.
- Otherwise it is not a constant expression.
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.
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
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.
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:
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.
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
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.
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:
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.
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
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:
isalnum()
and isspace()
required to be false for them ?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):
I believe that the answers should be:
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").
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:
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.
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
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
anduintmax_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.
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
anduintmax_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 andUINT_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:
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
anduintmax_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 andUINT_MAX
is 0xFFFF, the constant 0x8000 is signed and positive within a#if
expression even though it is unsigned in translation phase 7.
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
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 ?
(SIZE_MAX + 1)
.sizeof
with such a large argument.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.
One of:
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.
If the size is too large to fit in an object of type
size_t
, it is replaced by an implementation-defined value.
[#1a] The
sizeof
operator shall not be applied to an operand whose size, in bytes, is larger than the maximum value of the typesize_t
.
The implementation shall ensure that the type
size_t
is large enough to hold the result of all uses of thesizeof
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:
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.
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.
Authors: WG14 Convener (J. Benito)
Date: 2001-09-21
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_267.htm
- 5.1.2.3p12, example 4, expressions should be expression.
- 7.24.4.4.5p1
* s1
and* s2
should not have spaces following the*
s.- 7.24.6.1.1p3 "The
btowc
returns" should read "Thebtowc
function returns".- 7.24.6.1.2p3 "The
wctob
returns" should read "Thewctob
function returns".
In 5.1.2.3, paragraph #12 change last line of code fragment expressions to expression.
In 7.24.4.4.5, paragraph #1 remove the space following the
*
fors1
ands2
.In 7.24.6.1.1, paragraph #3 change:
"The
btowc
returns"to
"The
btowc
function returns"In 7.24.6.1.2, paragraph #3 change:
"The
wctob
returns"to
The
wctob
function returns"
Comment from WG14 on 2003-10-06:
In 5.1.2.3, paragraph #12 change expressions to expression in last line of code fragment.
In 7.24.4.4.5, paragraph #1 remove the space following the
*
fors1
ands2
.In 7.24.6.1.1, paragraph #3 change:
"The
btowc
returns"to
"The
btowc
function returns"In 7.24.6.1.2, paragraph #3 change:
"The
wctob
returns"to
The
wctob
function returns"
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
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.
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, abreak
orcontinue
statement has the appropriate effect. However, the code jumped over - including the controlling expressions in the case of awhile
orfor
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 9while if it is false it prints:
0 1 2 4 6 8 10
Comment from WG14 on 2006-03-29:
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.
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
orwhile
statement is not evaluated before entering the loop body, nor is clause-1 of afor
statement.
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
int
N
_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
uint
N
_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:
Change this section to read:
[#1] The typedef name
int
N
_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
uint
N
_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:
The first bullet point is false; while the second sentence is not a complete specification, it does not contradict the first sentence.
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.
The Committee believes that suggestion 2 (about unsigned types) should be considered for a future revision of the Standard.
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
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) and269
wchar_t
andwint_t
can be the same integer type.
Three possible solutions are:
wint_t
to be the promoted version of wchar_t
.%lc
to take promoted wchar_t
rather than wint_t
.Change the quoted line of 7.19.6.1#18 to:
fprintf(stdout, "|%13lc|\n", (wint_t) wstr[5]);
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 typewchar_t
;269) and
[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
, orX
conversion specifier applies to along int
orunsigned long int
argument; that a followingn
conversion specifier applies to a pointer to along int
argument; that a followingc
conversion specifier applies to an argument whose type is that resulting when the default argument conversions are applied to the typewchar_t
; that a followings
conversion specifier applies to a pointer to awchar_t
argument; or has no effect on a followinga
,A
,e
,E
,f
,F
,g
, orG
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 typewchar_t
* - is converted as if by anls
conversion specification with no precision and an argument that points to the initial element of a two-element array ofwchar_t
, the first element containing the argument to thelc
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 towchar_t
and written.
Comment from WG14 on 2002-03-07:
Change the quoted line of 7.19.6.1#18 to:
fprintf(stdout, "|%13lc|\n", (wint_t) wstr[5]);
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
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.
Append to 7.25.2.2.1#4:
If
desc
is zero, theiswctype
function returns zero (false).
Append to 7.25.3.2.1#4:
If
desc
is zero, thetowctrans
function returns the value ofwc
.
Comment from WG14 on 2002-05-15:
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.
The Committee believes this should be considered for a future revision of the Standard.
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
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.
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:
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.
Change footnote 93.
"...which removes any type qualifiers that were applied to the type category of the expression (for example, it removes
const
but notvolatile
from the typeint volatile * const
)."
__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
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 typewchar_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 ?
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 typewchar_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:
- are defined by ISO/IEC 10646, along with all amendments and technical corrigenda, as of the specified year and month; and
- have short identifiers that lie within the range of values that can be represented by the type
wchar_t
.
Comment from WG14 on 2002-03-07:
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 typewchar_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.
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
7.21.2.1#2 defines the operation of memcpy
as:
[#2] The
memcpy
function copies n characters from the object pointed to bys2
into the object pointed to bys1
.
7.21.2.3#2 defines the operation of strcpy
as:
[#2] The
strcpy
function copies the string pointed to bys2
(including the terminating null character) into the array pointed to bys1
.
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 data3.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
char
s 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
.
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 typeunsigned char
(and therefore every object representation is valid and has a different value). Where it is accessed through a parameter of typechar *
, each character shall be interpreted as if it had typechar
(and therefore, ifCHAR_MAX - CHAR_MIN + 1
is less thanUCHAR_MAX
, some byte values may be trap representations or be treated as equal to other values).
Comment from WG14 on 2003-10-22:
Our intention is that string and memory copies in the standard library should be
treated as unsigned char
, similar to 7.21.4.
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).
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
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.]
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:
Append to 7.6#6:
If no such macros are defined,
FE_ALL_EXCEPT
shall be defined as 0.
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
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.
In 7.19.1#5, fourth bullet, insert perror
after gets
.
Comment from WG14 on 2002-03-07:
In 7.19.1#5, fourth bullet, insert perror
after gets
.
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
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 classauto
orregister
.
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 ?
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 classauto
orregister
.
or:
[#3] Any object whose identifier is declarared in the declaration part of a
for
statement shall have storage classauto
orregister
.
Comment from WG14 on 2002-03-07:
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.
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
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:
- The basic character set shall be present and each character shall be encoded as a single byte.
- A byte with all bits zero shall be interpreted as a null character independent of shift state.
- A byte with all bits zero shall not occur in the second or subsequent bytes of a multibyte character.
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.
Replace the current last two bullets with a single one:
- A byte with all bits zero shall be interpreted as a null character independent of shift state. Such a byte shall not occur as part of any other multibyte character.
Comment from WG14 on 2002-03-07:
Replace the current last two bullets in 5.2.1.2 with a single bullet:
- A byte with all bits zero shall be interpreted as a null character independent of shift state. Such a byte shall not occur as part of any other multibyte character.
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
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.
C99 7.17 paragraph 2 specifies in part:
"...
wchar_twhich 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.
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_twhich 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_twhich 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_twhich 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 thewchar_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:
Change the last part of 7.17 paragraph 2 as follows:
"...
wchar_twhich 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."
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
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
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?1
, what should we return in case tm_isdst
is set to 0
or 1
?tm_isdst
is different from -1
?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 ?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.
tm_isdst
to 0
and return the time_t
value corresponding to 2:30 AM Standard Time.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.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).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:
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 onestruct tm
value hastm_isdst=1
and the other hastm_isdst=0
(regardless of the date stored in thestruct tm
values).See footnote 267.
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
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.
Comment from WG14 on 2003-03-06:
In 7.23.1 Components of time, remove the word "constant" in the 2nd paragraph.
Authors: J11, Douglas Walls (US)
Date: 2002-06-11
Status: Fixed
Fixed in: C99 TC2
Converted from: summary-c99.htm, dr_282.htm
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.
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.
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:
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 memberd
. 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 byp
behaves, for most purposes, as ifp
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 behaviorThe initialization of
t2
is invalid (and violates a constraint) becausestruct s
is treated as if it does not contain memberd
. The assigment tot1.d[0]
is probably undefined behaviour, but it is possible thatsizeof (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
ands2
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 firstsizeof (struct s)
bytes of the structure, these might be copied or simply overwritten with indeterminate values.
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.]
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.
[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:
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.
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
<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>.
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?
Comment from WG14 on 2004-03-05:
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>
.
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
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.
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:
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.
Authors: WG 14, Fred Tydeman (USA)
Date: 2003-04-13
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_286.htm
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.
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
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:
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.
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)'.
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
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.
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:
Flags are not objects, thus the constraint on modifying objects doesn't apply to flags.
As noted in the response to DR 087, function calls in the same expression do not overlap. This has not changed for C99.
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.
Authors: BSI, Clive Feather
Date: 2003-10-21
Reference document: N1012
Status: Closed
Converted from: summary-c99.htm, dr_288.htm
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).
Append to 7.24.6.3.2#4:
(size_t)(-3)
if the multibyte sequence converted by the previous call with the samembstate_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:
This is not really a defect, but a deficiency which could be addressed in a future release of the C Standard.
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
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:
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-liststatic
assignment-expression]
FLT_EVAL_METHOD
and extra precision and/or rangeAuthors: WG 14, Fred Tydeman (USA)
Date: 2003-08-29
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_290.htm
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
is1
, then the product of twofloat _Complex
operands is represented in thedouble _Complex
format, and its parts are evaluated todouble
.
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
andd2
are required to have been converted tofloat
.
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 todouble
orlong double
, or adouble
is promoted tolong double
, its value is unchanged.2 When a
double
is demoted tofloat
, along double
is demoted todouble
orfloat
, 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
.
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:
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.
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.
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
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
, andnearbyint
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 thenearbyint
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 thenearbyint
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 forx
finite and the function value infinite.nextafter(x, y)
raises the underflow and inexact floating-point exceptions for the function value subnormal or zero andx != 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 forx
finite and the function value infinite.nextafter(x, y)
raises the underflow floating-point exception for the function value zero andx != y
.nextafter(x, y)
may raise the underflow floating-point exception for the function value subnormal andx != 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:
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.
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).
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
Change the use of variable to object in those instances where the Standard is referring to an object.
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 asint
.
to
Therefore, for full portability, the object
c
should be declared asint
.
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
anddouble_t
variables increases the likelihood of translation-time computation.
to
Use of
float_t
anddouble_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:
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
double complex
instead of complex
in an exampleAuthors: Tydeman (US)
Date: 2003-10-24
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_293.htm
6.7.8, paragraph 24, example 1.
complex c = 5 + 3 * Ishould changed to
double complex c = 5 + 3 * I
Change complex
to double complex
in the example.
Comment from WG14 on 2004-03-01:
6.7.8, paragraph 24, example 1.
complex c = 5 + 3 * Ichanged to
double complex c = 5 + 3 * I
restrict
keywordAuthors: INCITS, Greg Davis, Green Hills Software
Date: 2003-08-14
Status: Closed
Converted from: summary-c99.htm, dr_294.htm
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:
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.
D
is the declaration for the identifier a
and T
is char
P
is the object designated by a
B
is the block of main
, whose execution includes the call to copy()
L
is the expression dest[i]
in copy()
&L == dest+i
which is based on a
, because dest
gets its value from a
upon entry to copy()
<-- Key pointX
is the object designated by dest[i]
(which is a[i]
)X
is modified during the execution of main
The requirements in the specification are then:
T
is not const-qualified.X
...X
shall be considered also to modify P
, for the purposes of this subclause.P
itself (which is the pointer object a
) is not designated by means of another restrict-qualified pointer.P
is assigned the value of a pointer expression E
that is based on another restricted pointer object P2
, ...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.]
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
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:
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.
Change 6.7p7
in the case of function arguments (including in prototypes)
to:
in the case of function parameters (including in prototypes)
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
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 macroHUGE_VAL
,HUGE_VALF
, or ...; if the integer expressionmath_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).
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 macroHUGE_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:
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 zInf -> 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 INFInf -> 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 finitefinite -> 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.
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 macroHUGE_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).
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
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:
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.
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.
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:
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.
unsigned long long
rangeAuthors: 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
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.
Comment from WG14 on 2007-09-06:
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.
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".
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
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.
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.
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:
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
.
7.22p5 Add ", except modf
" after "<math.h>
"
7.22p7 (3rd line from end), cabs(fc)
should be changed to fabs(fc)
.
Authors: WG 14, Fred Tydeman (USA)
Date: 2004-08-26
Status: Closed
Converted from: summary-c99.htm, dr_300.htm
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.
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.
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:
The Committee consensus is this is not a defect, and that this DR imposes a new requirement on implementations.
This is not really a requirement, but an area to be investigated that could be addressed in a future revision of the C Standard.
Authors: WG 14, Fred Tydeman (USA)
Date: 2004-08-27
Status: Closed
Converted from: summary-c99.htm, dr_301.htm
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)?
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 infinityAll 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_UNDERFLOWis 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:
feraiseexcept(FE_BLUEMOON)
succeeds,fetestexcept(FE_BLUEMOON)
returns the current status of that "exception",feclearexcept(FE_BLUEMOON)
succeeds,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_UPWARDis 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.
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()
andfeclearexcept()
succeed for a given FE_* exception is not sufficient.
FE_INVALID
should be a side-effect of:
- operations on signaling NaN or trap representation,
- adding infinities with different signs,
- subtracting infinities with the same signs,
- multipling zero by infinity,
- dividing zero by zero and infinity by infinity,
- remainder (x REM y), where x is infinite or y is zero,
- square root of a negative number (excluding -0.0),
- converting a too large to represent floating value to an integer [both signed and unsigned], e.g., int i = INFINITY; unsigned int ui = -1.0;
- comparison with a relational operator (<, <=, >=, >) when (at least) one of the operands is a NaN.
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()
andfesetround()
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:
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.
This is not really a defect, but an area which could be addressed in a future revision of the C Standard.
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
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.
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 singleletternondigit. The first character shallbe a letternot 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:
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 singleletternondigit. The first character shallbe a letternot be a digit. The implementation may ignore the distinctions of alphabetical case and restrict the mapping to eight significant characters before the period.
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
The sentence describing a preprocessing directive is fearsomely long.
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:
TC2 (and specifically DR 250) changed that sentence into a definition.
Change 6.10p2:
A preprocessing directive consists of a sequence of preprocessing tokens
that begins withthat 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.
#if
directivesAuthors: 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
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.
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:
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).
#if
directivesAuthors: 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
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.)
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-number0
, and then each preprocessing token is converted into a token.
Comment from WG14 on 2006-03-05:
It is clear from the standard (in particular, the phases of translation) that there are not yet any keywords at the point in question.
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-number0
, and then each preprocessing token is converted into a token.
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
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.
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:
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.
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
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".
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-linedefines a function-like macro with
argumentsparameters, similar syntactically to a function call.
Comment from WG14 on 2006-03-05:
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-linedefines a function-like macro with
argumentsparameters, whose use is similar syntactically to a function call.
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
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.
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:
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.
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
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.
Change 5.2.1.1p1:
All occurrences in a source fileBefore any other processing takes place, each occurrence of one of the following sequences of three characters (called trigraph sequences12))areis replaced with the corresponding single character.
Comment from WG14 on 2006-03-05:
Change 5.2.1.1p1:
All occurrences in a source fileBefore any other processing takes place, each occurrence of one of the following sequences of three characters (called trigraph sequences12))areis replaced with the corresponding single character.
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
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).
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:
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]
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
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.
Comment from WG14 on 2007-09-06:
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.
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.
[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.
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
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?
Comment from WG14 on 2006-04-04:
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
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.
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
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.
Comment from WG14 on 2006-03-05:
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.
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
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.
Comment from WG14 on 2008-09-12:
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.
See N1237.
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.
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.
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.
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
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 assigned int
or the same type asunsigned 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.
Comment from WG14 on 2007-10-10:
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.
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 tosizeof(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. |
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.
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 anint
;
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
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.
Comment from WG14 on 2006-03-05:
The Committee believe the answers to Q1 & 2 are yes, and that the Standard is unclear with respect to 3 & 4.
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.
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
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?
Comment from WG14 on 2006-04-04:
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.
(double)0.1f
with FLT_EVAL_METHOD
being 2Authors: WG 14, Fred Tydeman (USA)
Date: 2004-10-27
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_318.htm
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.
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 todouble
orlong double
, or adouble
is promoted tolong double
, its value is unchanged.When a
double
is demoted tofloat
, along double
is demoted todouble
orfloat
, 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.
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:
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.
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
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:
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.
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:
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.
Authors: Willem Wakker
Date: 2005-05-02
Status: Fixed
Fixed in: C99 TC3
Converted from: summary-c99.htm, dr_320.htm
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.
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:
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.
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
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.
C99 7.17 paragraph 2 specified (before TC2) in part:
"...
wchar_twhich 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_twhich 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.
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_twhich 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:
Change the last part of 7.17 paragraph 2 as follows:
wchar_twhich 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__
.
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
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
).
Rescind ISO/IEC 9899:1999/Cor.2:2004 change #67 which states:
Page 263, 7.19.6.1
In paragraph 5, item 4, insertperror
aftergets
.
Comment from WG14 on 2006-10-25:
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.
Rescind ISO/IEC 9899:1999/Cor.2:2004 change #67 which states:
Page 263, 7.19.1
In paragraph 5, item 4, insertperror
aftergets
.
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?
Comment from WG14 on 2006-10-25:
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.
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.
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.
In 7.3.1 of C99+TC1+TC2, replace paragraphs 3 and 4 with:
[#3] The macros
imaginary
and
_Imaginary_Iare defined if and only if the implementation supports imaginary types;165 if defined, they expand to
_Imaginary
and a constant expression of typeconst float _Imaginary
with the value of the imaginary unit.[#4] The macro
Iexpands 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
andI
.165A specification for imaginary types is in informative annex G.
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.
Comment from WG14 on 2006-10-25:
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:
\
as the start of an escape sequence\
as a literal characterThe 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.
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.
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 typeint
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.
Clarification Required.
Change 7.21.6.2, p2 from:
The strerror function maps the number in
errnum
to a message string. Typically, the values forerrnum
come fromerrno
, butstrerror()
shall map any value of typeint
to a message.
To:
The strerror function maps the number in
errnum
to a message string. If the value oferrnum
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 forerrnum
come fromerrno
, but strerror shall map any value of type int to a message.
Comment from WG14 on 2006-10-25:
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.
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.
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 bytimeptr
into a string in the form, provided the broken-down time in the fields of the structure pointed to bytimeptr
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 bytimeptr
contain values that are outside the normal ranges, the behavior ofasctime()
is undefined. If the calculated year exceeds four digits, the behavior is undefined.
Comment from WG14 on 2007-09-06:
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.
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 bytimeptr
contain values that are outside the normal ranges*, the behavior ofasctime()
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".
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
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.
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:
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).
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
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.
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:
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)
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
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), andnexttoward
(as per C99 andnextafter
). Note, even thoughnextafter
andnexttoward
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
, andfmin
.There are several functions that are dependent on the current rounding direction:
sqrt
(as per IEEE-754),nearbyint
,rint
,lrint
,llrint
, andfma
.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
, andfdim
.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), andremquo
(when subnormal results are not supported).
Comment from WG14 on 2008-09-12:
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.
It was noted that there is no rounding requirements for some of the cases mentioned
We believe that the proposed TC is correct, and nobody has found any additional rounding requirements.
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.
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
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:
Comment from WG14 on 2007-10-30:
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).
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.
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
Regarding 7.12.1 para 2,
which says that if both
errno
and fp exceptions are used, and if a domain error occurs, thenerrno
getsEDOM
and the fp exception isFP_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.
Comment from WG14 on 2007-10-10:
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.
In London the consensus was that no change is required.
The Standard seems clear, no change is needed.
gets
is generally unsafeAuthors: 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
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.
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:
The Committee thinks that the programming community would be better served by
flagging the gets()
function as deprecated.
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
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
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.
Add, in proper alphabetic order in the list in 6.10.8 para 2:
__STDC_MB_MIGHT_NEQ_WC__
The integer constant1
, intended to indicate that there might be some characterx
in the basic character set, such that'
x
'
need not be equal toL'
x
'
.
Comment from WG14 on 2007-09-06:
Add, in proper alphabetic order in the list in 6.10.8 paragraph 2:
__STDC_MB_MIGHT_NEQ_WC__
The integer constant1
, intended to indicate that, in the encoding forwchar_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.
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
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.
Comment from WG14 on 2008-04-16:
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.
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.
This work could possibly fit into the type generic/overloading project that needs to be completed for C1X.
This issue will be addressed in a future revision of the C standard. See WG 14 document Nxxx.
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
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.
Comment from WG14 on 2008-07-21:
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
).
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
.
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
.
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 calltmpnam()
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)"
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:
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."
stdio.h
macro definition problemsAuthors: Austin Group, Nick Stoughton (US)
Date: 2007-02-28
Status: Closed
Converted from: summary-c99.htm, dr_337.htm
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.
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:
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.
All of these constants already have required minimum values that are positive, non-zero. No changes are required.
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
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.
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:
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.
See WG14 e-mail SC22WG14.11380
While some agreed with the comments in this email others did not.
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.
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
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
).
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:
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.
This defect report is answered by DR 328.
Constraints and Semantics are the same as 6.7.8 Initialization
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
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.
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:
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.
No consensus was reached on the words from N1238.
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.
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).
[*]
in abstract declaratorsAuthors: 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
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.
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:
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.
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
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
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.
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:
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
The consensus at this meeting is that this defect should be linked with defect report 340.
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
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.)
6.7.8 paragraph 15, change "wchar_t
" to "a qualified or unqualified version of
wchar_t
".
Comment from WG14 on 2007-09-07:
Change 6.7.8 paragraph 15:
"
wchar_t
"
to
"a qualified or unqualified version of
wchar_t
".
Authors: WG21, Clark Nelson
Date: 2007-04-23
Status: Fixed
Fixed in: C11
Converted from: summary-c99.htm, dr_344.htm
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.
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:
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
Authors: Rob Arthan <UK>, Derek Jones (UK)
Date: 2007-04-23
Status: Fixed
Fixed in: C11
Converted from: summary-c99.htm, dr_345.htm
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.
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:
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.
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
C++ 3.3.2p2 has three sentences (words irrelevant to C are deleted):
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.
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 ofend 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.