*/ } ul /* Whole unordered list */ { } ul li /* Unordered list item */ { } ol /* Whole ordered list */ { } ol li /* Ordered list item */ { } hr {} /* ---- Some span elements --- */ sub /* Subscripts. Pandoc: H~2~O */ { } sup /* Superscripts. Pandoc: The 2^nd^ try. */ { } em /* Emphasis. Markdown: *emphasis* or _emphasis_ */ { } em > em /* Emphasis within emphasis: *This is all *emphasized* except that* */ { font-style: normal; } blockquote > p > em /* Emphasis within emphasis: *This is all *emphasized* except that* */ { font-style: normal; } blockquote > * > p > em /* Emphasis within emphasis: *This is all *emphasized* except that* */ { font-style: normal; } blockquote > p > ins > em /* Emphasis within emphasis: *This is all *emphasized* except that* */ { font-style: normal; } blockquote > * > p > ins > em /* Emphasis within emphasis: *This is all *emphasized* except that* */ { font-style: normal; } /* ---- Links (anchors) ---- */ a /* All links */ { /* Keep links clean. On screen, they are colored; in print, they do nothing anyway. */ text-decoration: none; } @media screen { a:hover { /* On hover, we indicate a bit more that it is a link. */ text-decoration: underline; } } @media print { a { /* In print, a colored link is useless, so un-style it. */ color: black; background: transparent; } a[href^="http://"]:after, a[href^="https://"]:after { /* However, links that go somewhere else, might be useful to the reader, so for http and https links, print the URL after what was the link text in parens */ content: " (" attr(href) ") "; font-size: 90%; } } /* ---- Images ---- */ img { /* Let it be inline left/right where it wants to be, but verticality make it in the middle to look nicer, but opinions differ, and if in a multi-line paragraph, it might not be so great. */ vertical-align: middle; } div.figure /* Pandoc figure-style image */ { /* Center the image and caption */ margin-left: auto; margin-right: auto; text-align: center; font-style: italic; } p.caption /* Pandoc figure-style caption within div.figure */ { /* Inherits div.figure props by default */ } /* ---- Code blocks and spans ---- */ pre, code { background-color: #fdf7ee; /* BEGIN word wrap */ /* Need all the following to word wrap instead of scroll box */ /* This will override the overflow:auto if present */ white-space: pre-wrap; /* css-3 */ white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */ white-space: -pre-wrap; /* Opera 4-6 */ white-space: -o-pre-wrap; /* Opera 7 */ word-wrap: break-word; /* Internet Explorer 5.5+ */ /* END word wrap */ } pre /* Code blocks */ { /* Distinguish pre blocks from other text by more than the font with a background tint. */ padding: 0.5em; /* Since we have a background color */ border-radius: 5px; /* Softens it */ /* Give it a some definition */ border: 1px solid #aaa; /* Set it off left and right, seems to look a bit nicer when we have a background */ margin-left: 0.5em; margin-right: 0.5em; } pre.yacc, code.yacc { background-color: #f0f0f0; } pre.yacc /* Code blocks */ { /* Distinguish pre blocks from other text by more than the font with a background tint. */ padding: 0.0em; /* Since we have a background color */ border-radius: 5px; /* Softens it */ /* Give it a some definition */ border: 0px solid #aaa; /* Set it off left and right, seems to look a bit nicer when we have a background */ margin-left: 0.0em; margin-right: 0.0em; } @media screen { pre { white-space: pre; /* Dotted looks better on screen and solid seems to print better. */ border: 1px dotted #777; } } code /* All inline code spans */ { } p > code, li > code /* Code spans in paragraphs and tight lists */ { /* Pad a little from adjacent text */ padding-left: 2px; padding-right: 2px; } li > p code /* Code span in a loose list */ { /* We have room for some more background color above and below */ padding: 2px; } span.option { color: blue; text-decoration: underline; } /* ---- Math ---- */ span.math /* Pandoc inline math default and --jsmath inline math */ { /* Tried font-style:italic here, and it messed up MathJax rendering in some browsers. Maybe don't mess with at all. */ } div.math /* Pandoc --jsmath display math */ { } span.LaTeX /* Pandoc --latexmathml math */ { } eq /* Pandoc --gladtex math */ { } /* ---- Tables ---- */ /* A clean textbook-like style with horizontal lines above and below and under the header. Rows highlight on hover to help scanning the table on screen. */ table { border-collapse: collapse; border-spacing: 0; /* IE 6 */ border-bottom: 2pt solid #000; border-top: 2pt solid #000; /* The caption on top will not have a bottom-border */ /* Center */ margin-left: auto; margin-right: auto; } thead /* Entire table header */ { border-bottom: 1pt solid #000; background-color: #eee; /* Does this BG print well? */ } tr.header /* Each header row */ { } tbody /* Entire table body */ { } /* Table body rows */ tr { } tr.odd:hover, tr.even:hover /* Use .odd and .even classes to avoid styling rows in other tables */ { background-color: #eee; } /* Odd and even rows */ tr.odd {} tr.even {} td, th /* Table cells and table header cells */ { vertical-align: top; /* Word */ vertical-align: baseline; /* Others */ padding-left: 0.5em; padding-right: 0.5em; padding-top: 0.2em; padding-bottom: 0.2em; } /* Removes padding on left and right of table for a tight look. Good if thead has no background color*/ /* tr td:last-child, tr th:last-child { padding-right: 0; } tr td:first-child, tr th:first-child { padding-left: 0; } */ th /* Table header cells */ { font-weight: bold; } tfoot /* Table footer (what appears here if caption is on top?) */ { } caption /* This is for a table caption tag, not the p.caption Pandoc uses in a div.figure */ { caption-side: top; border: none; font-size: 0.9em; font-style: italic; text-align: center; margin-bottom: 0.3em; /* Good for when on top */ padding-bottom: 0.2em; } /* ---- Definition lists ---- */ dl /* The whole list */ { border-top: 2pt solid black; padding-top: 0.5em; border-bottom: 2pt solid black; } dt /* Definition term */ { font-weight: bold; } dd+dt /* 2nd or greater term in the list */ { border-top: 1pt solid black; padding-top: 0.5em; } dd /* A definition */ { margin-bottom: 0.5em; } dd+dd /* 2nd or greater definition of a term */ { border-top: 1px solid black; /* To separate multiple definitions */ } /* ---- Footnotes ---- */ a.footnote, a.footnoteRef { /* Pandoc, MultiMarkdown footnote links */ font-size: small; vertical-align: text-top; } a[href^="#fnref"], a.reversefootnote /* Pandoc, MultiMarkdown, ?? footnote back links */ { } @media print { a[href^="#fnref"], a.reversefootnote /* Pandoc, MultiMarkdown */ { /* Don't display these at all in print since the arrow is only something to click on */ display: none; } } div.footnotes /* Pandoc footnotes div at end of the document */ { } div.footnotes li[id^="fn"] /* A footnote item within that div */ { } table tr td,th { border-right: 1px solid; border-left: 1px solid; } /* You can class stuff as "noprint" to not print. Useful since you can't set this media conditional inside an HTML element's style attribute (I think), and you don't want to make another stylesheet that imports this one and adds a class just to do this. */ @media print { .noprint { display:none; } }
2025-09-07
integration into IS ISO/IEC 9899:202y
C document ID: C4172
document number | date | comment |
---|---|---|
n3543 | 202504 | original proposal |
along the lines vote in Brno for integer types 22/0/6 | ||
n3707 | 202509 | remove floating types |
place in <stdlib.h> |
||
make the interfaces unsequenced |
Generic features to compute minimum and maximum value of two given values is notoriously challenging in C. Motivating examples for this proposal are the following
constexpr size_t n = SIZE_MAX;
static double A[stdc_max(n, 1)];
enum { small = stdc_min(something, -1), };
That is, minimum and maximum features that are usable where a integer
constant expression is needed and that are able to mix comparison of
signed (1
and
-1
)
and unsigned (n
and perhaps something
) without hickup.
The difficulties with such features are as follows
We propose to add type-generic macros that solve all these problems for all integer value and type combinations. 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 stdc_min
chooses the signed
type for the result.
The proposed features have to be implemented side effect free and
thus, seen as function interfaces, they should be pure in the CS sense
of the term. So, as we have already have done for the bit manipulation
macros, for these new interfaces we add the [[unsequenced]]
attribute.
For convenience, we propose to add the features to the <stdlib.h>
header, 7.25.7 “Integer arithmetic functions”, with the idea this header
already contains functions that operate on integers. But, 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).
The choice for the name is guided by the fact that min
and max
identifiers are abundantly used in user
code, not only for functions or macros that perform these operations,
but also as variable names that store the respective minimum or maximum
value in a given situation. The prefix stdc_
, which is reserved for identifiers
with external linkage, seemed the most natural one: sufficiently short
and unambiguous.
Implementations of minimum and maximum functions there are plenty. Even the current C standard provides a handful of slightly different interfaces for maximum functions, but only for floating types. 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
resolves 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 is available on the WG14 git (and
that we 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 relatively
small effort. Besides a lot of C23-only features, this reference
implementation uses only the __COUNTER__
pseudo macro (which is accepted
for inclusion into C2Y).
We also provide an alternative implementation that uses compound
expressions which could easily be replaced with lambdas or other forms
of function literals. The advantage of that is that it avoids declaring
a whole bunch of auxiliary inline functions. Its disadvantage is that
this implementation with extended expressions currently doesn’t work for
integer constant expressions in file scope. This is due to a
restriction in gcc that forbids compound expressions in file scope, even
if they are only present in a dead branch of a _Generic
expression.
Our expectation is that compilers will provide buildins for these features and that the macros proposed here will then only serve as stubs to ensure standard conformance.
In 7.25, bump the value of __STDC_VERSION_STDLIB_H__
.
Then add a new clause
7.25.7.3 Minimum and maximum operation type-generic macros
1 The following macros perform minimum and maximum operations. These operations are applicable to pairs of values of any integer type. In the following
A
andB
denote the promoted type of the first and second argument of an invocation, respectively.
2 Synopsis
#include <stdlib.h>
(A a, B b) [[unsequenced]];
minType stdc_min(A a, B b) [[unsequenced]]; maxType stdc_max
Description
3 After argument promotion, these type-generic macros compute the minimum and maximum value of their arguments. If both arguments are integer constant expressions, the macro invocation is an integer constant expressions, too.
4 The result typemaxType
is the common real type of the typesA
andB
after the usual arithmetic conversions (6.3.2.8). The result typeminType
is determined as follows:
- If
maxType
is an unsigned type and if one of the typesA
orB
is signed,minType
is that signed type.- Otherwise,
minType
is the same asmaxType
.
Returns
5 The result of the operation is the value of the mathematically lesser (respectively greater) argument converted to typeminType
(respectivelymaxType
).
6 NOTE The types
minType
andmaxType
are able to represent the mathematical result of the corresponding operation.
7 Example
#include <stdlib.h>
constexpr size_t n = SIZE_MAX;
static double A[stdc_max(n, 1)];
constexpr auto max1 = stdc_max(n, 0); // (size_t)n
constexpr auto min1 = stdc_min(n, 0); // (signed int)0
constexpr auto max2 = stdc_max(n, 0u); // (size_t)n
constexpr auto min2 = stdc_min(n, 0u); // (size_t)0
constexpr auto max3 = stdc_max(n, (char)0); // (size_t)n
constexpr auto min3 = stdc_min(n, (char)0); // (size_t)0 or (signed int)0
constexpr auto max4 = stdc_max(3wb, 7wbu); // (unsigned _BitInt(3))7
constexpr auto min4 = stdc_min(3wb, 7wbu); // (signed _BitInt(3))3
constexpr auto max5 = stdc_max(-1wb, 255wbu); // (unsigned _BitInt(8))255
constexpr auto min5 = stdc_min(-1wb, 255wbu); // (signed _BitInt(2))-1
constexpr auto max6 = stdc_max(-1wbu, 255wbu); // (unsigned _BitInt(8))255
constexpr auto min6 = stdc_min(-1wbu, 255wbu); // (unsigned _BitInt(8))1
Here, the array length expression ofA
computes the maximum of two integer constant expressions and is thus an integer constant expression, too. Formin1
, one of the promoted arguments tostdc_min
has a signed type, so the result type is that signed type. Conversely, formin2
both promoted arguments have an unsigned type, and so the result is the common real type. The type ofmin3
depends on whether or notchar
can hold negative values and of its width. Ifchar
has no negative values and the same width asint
it promotes tounsigned int
and thus the result type issize_t
; otherwise the result issigned int
. The type ofmax4
is the common real type ofsigned _BitInt(3)
(for3wb
) andunsigned _BitInt(3)
(for7wbu
) which isunsigned _BitInt(3)
. Formin4
with the same arguments, the result type is signed type of the two,signed _BitInt(3)
. Formin5
, since one of the types is signed the result is that typesigned _BitInt(2)
. Formin6
,-1wbu
is the maximum value ofunsigned _BitInt(1)
which is1
; since both of the types are unsigned the result is converted to the common real typeunsigned _BitInt(8)
.