Jens Gustedt, INRIA and ICube, France
2025年04月29日
integration into IS ISO/IEC 9899:202y
| document number | date | comment |
|---|---|---|
| n3543 | 202504 | this document |
Generic features to compute minimum and maximum value of two given values is notoriously challenging in C.
fmin tg macro of <tgmath.h>)
may result in loss of precision.We propose to add type-generic macros that solve all these problems. Namely:
In particular the choice for the minimum differs from the usual
arithmetic conversions. If one type is signed and the other is unsigned
the macro ckd_min chooses the signed
type for the result.
Possible problems arise
For these cases we propose different variants, one that rejects translation in these cases, one that makes these cases implementation-defined, including the possibility to reject translation, and one that has undefined behavior.
For convenience, we propose to add the features to the <stdckdint.h>
header with the idea this header contains operations that are merely
language features that always have defined behavior. The suggested
wording could easily be adapted to be placed in a different header
(clause 7) or even to be introduced as proper operators (clause 6).
Implementations of minimum and maximum functions there are plenty. Even the current C standard provides a handful of slightly different interfaces, even for type-generic ones. Then, in the field an abundant number of implementations of varying properties and quality are added to that picture.
We are not aware of an implementation of these functionalities that
all the problems that are listed in the introduction. In particular,
none of them seems to provide an integer constant expression where this
would be possible. This is all the more surprising as that property has
a clear demand (in particular for array lengths) and as providing macros
that have that property is not too difficult by using either
implementation-specific extensions (such as gcc’s __builtin_constant_p) and/or playing tricks
with _Generic.
The goal of this paper is to propose a unification to all these interfaces and their behavior, such that programmers find reliable implementations of these features in their C library. The reference implementation that we maintain (and are able to provide on request) is not meant to suggest any particular way in which these features should be implemented, but only to prove that an implementation is possible as of today with minimal effort.
In 7.20.1, bump the value of __STDC_VERSION_STDCKDINT_H__.
Then add a new clause
(追記)(追記ここまで) (追記)7.20.4 Minimum and maximum operation type-generic macros
(追記ここまで) (追記)Synopsis
#include <stdckdint.h>
minType ckd_min(typeA a, typeB b);
maxType ckd_max(typeA a, typeB b);(追記ここまで)Description
(追記) 2 These type-generic macros compute the minimum and maximum value of their arguments, respectively. If both arguments are integer constant expressions, the macro call expression is also an integer constant expressions. (追記ここまで)
(追記) 3 The result type(追記)maxTypeistypeof(a+b). The result typeminTypeis determined as follows: (追記ここまで)
- If
maxTypeis an unsigned integer type and if one oftypeAortypeBhas negative values,minTypeistypeof(+a)ortypeof(+b), respectively.
(追記ここまで) (追記)
- Otherwise,
minTypeis the same asmaxType.
(追記ここまで)Returns
(追記) 4 If none of the arguments is a NaN, the result of the operation is the mathematically lesser (respectively greater) argument converted to type(追記)minTypeandmaxType, respectively. Otherwise, if one of the arguments is a signaling NaN, the "domain error" floating point exception is raised and the result is a signaling NaN of the appropriate type. Otherwise, if one of the arguments is a quiet NaN, no floating point exception is raised and the result is a quiet NaN of the appropriate type. (追記ここまで)
(追記ここまで)5 NOTE 1 If both arguments have integer type,
minTypeandmaxTypeare able to represent the mathematical result of the respective operation.
(追記) 6 NOTE 2 For other type combinations (e.g combining auint64_tinteger and an ISO/IEC 60559 binary64 floating point type) the typesminTypeandmaxType(here the floating point type) is not able to hold the precise result of the operations for all possible combinations of argument values. (追記ここまで)
(追記) 7 Example (追記ここまで)(追記)
#include <ckdint.h>
constexpr size_t n = SIZE_MAX;
static double A[ckd_max(n, 1)]; // valid
constexpr auto ms = ckd_min(n, 0); // valid, type is int
constexpr auto mu = ckd_min(n, 0u); // valid, type is size_t
constexpr auto mc = ckd_min(n, (char)0); // valid, type depends on architecture
constexpr auto md = ckd_min(n, 0.0); // type double, possibly invalid(追記) Here, the array length expression ofAcomputes the maximum of two integer constant expressions and is thus an integer constant expression, too. Forms, one of the arguments tockd_minhas a signed type, so the result type is that signed type. Conversely, formuboth arguments have an unsigned type, and so the result is the common real type. The type ofmcdepends on whether or notcharadmits negative values; if so, the result type isint, otherwise it issize_t. Formdthe common real type isdouble, but it is implementation-defined if the value ofSIZE_MAXis representable without loss of precision in that type. (追記ここまで)
It is important to add the possibility to reject combinations that cannot properly represent the mathematical result in all cases. Therefore one of the following variants should be added to the text above.
Add to 7.20.4 as described above
(追記) 3′ IftypeAandtypeBdo not have a common real type or if the result type of the operation is not able to hold the result for all possible value combinations oftypeAandtypeB, the program translation fails. (追記ここまで)
Add to the end of 7.20.4 p7 (example) as described above
(追記)
If it is, all possible value combinations of values are representable in
the result and the definition of md is
accepted; otherwise the program translation fails.
(追記ここまで)
Add to J .3.16, architecture specific behavior
(追記)
- If calls to the
ckd_minandckd_maxtype-generic macros with certain combinations of integer and floating arguments are accepted (7.20.4). (追記ここまで)
Add to 7.20.4 as described above
(追記) 3′ IftypeAandtypeBdo not have a common real type it is implementation-defined if the program translation fails or if the typesminTypeandmaxTypeare chosen in an implementation-defined way. If the result type of the operation is not able to hold the result for all possible value combinations oftypeAandtypeB, it is implementation-defined if the operation is accepted, possibly resulting in a loss of precision, or if the program translation fails. (追記ここまで)
Add to the end of 7.20.4 p7 (example) as described above
(追記) If it is, the definition ofmdis accepted. Otherwise it is implementation-defined if the program translation fails or ifmdhas the value(double)SIZE_MAX. (追記ここまで)
Add to J .3.15, implementation-defined behavior
(追記)(追記ここまで)
- The behavior of calls to the
ckd_minandckd_maxtype-generic macros if their arguments do not have a common real type or if the result type cannot represent all possible results (7.20.4).
Add to 7.20.4 as described above
(追記) 3′ IftypeAandtypeBdo not have a common real type or if the result type of the operation is not able to hold the result for all possible value combinations oftypeAandtypeB, the behavior is undefined. (追記ここまで)
Add to the end of 7.20.4 p7 (example) as described above
(追記)
If it is, the definition of md is
valid, otherwise the behavior is undefined.
(追記ここまで)
Add to J .2, undefined behavior
(追記)(追記ここまで)
- The behavior of calls to the
ckd_minandckd_maxtype-generic macros if their arguments do not have a common real type or if the result type cannot represent all possible results (7.20.4).