December 14, 2025·4 min read·engineeringcmacrosintegersstandards

C's proposed min and max macros compare mathematical values

N3762 combines integer promotions, mathematical comparison, and constant-expression support. Its minimum result type deliberately differs from the usual arithmetic conversions.

A minimum macro can return the wrong mathematical answer even when neither argument has a side effect. Mixing signed and unsigned values can change the comparison before the conditional expression selects a result. Adding protection against repeated evaluation solves a different problem. A useful standard facility has to define both the comparison and the result type, while remaining usable in constant expressions.

Jens Gustedt's N3762 proposal addresses that combination for integer arguments. The WG14 document log lists the third revision on December 14. The paper's own December 7 date describes the document internally. Its subject is proposed stdc_min and stdc_max type-generic macros, with wording intended for the next C revision.

I like C's compact expression syntax, but a familiar macro name says little about its semantics. The same apparent operation can duplicate an argument, convert a negative value to unsigned, or stop being an integer constant expression. Standardizing the operation is useful if it removes those differences from ordinary calling code.

Comparison and result type are separate decisions

N3762 applies integer promotions to the arguments first. It then compares their mathematical values. That second step is crucial because it avoids treating an ordinary mixed-type comparison as an adequate definition of the mathematical minimum or maximum.

The minimum's result type has a special rule. If one promoted argument type is signed and the other unsigned, the result type is the signed one. Otherwise it uses the common real type determined by the usual arithmetic conversions. The maximum uses that common real type in all cases described by the wording.

The asymmetry is deliberate. When a negative signed value competes with a nonnegative unsigned value for the minimum, the signed value must remain representable in the result. A rule that first converted both operands to an unsigned common type could change the comparison and lose the intended result before selection.

For example, the proposal's intended operation can be illustrated with a negative signed argument and a small unsigned argument. These calls describe draft interfaces, not functions already required by C23.

stdc_min(-1, 5u)
stdc_max(-1, 5u)

Under the proposed rules, the first result is minus one with type int, and the second is five with type unsigned int. The result-type decision follows the selected operation. Requiring both macros to share a single type-selection rule would miss the design issue that the paper addresses.

Constant expressions are part of the interface

The proposal requires an invocation with two integer constant expression arguments to remain an integer constant expression. That makes the facility usable in contexts that require such an expression. Gustedt's motivating examples include array lengths and enumerator values, where an ordinary runtime helper function would not provide the same interface.

The paper discusses implementation techniques that protect against duplicate evaluation but lose this property. In particular, a compound-expression implementation can encounter restrictions at file scope. A macro that behaves well in a function body can consequently fail in exactly the declaration contexts that motivate a standard solution.

N3762 does not prescribe one implementation. Its reference work demonstrates feasibility, and the paper expects compilers to provide builtins behind the public macros. The standardization target is the observable behavior of the interface. An implementation can choose machinery appropriate to its compiler as long as it meets that behavior.

That is a useful distinction for library maintainers. A public macro can give a standard name to behavior that needs compiler cooperation. The fact that it looks like a function call does not require it to be implemented as a single ordinary function, especially when its result type and constant-expression status depend on the arguments.

The revision keeps the scope to integers

The document history says the previous revision removed floating types and placed the interfaces in stdlib.h. N3762 revises wording for promotions. Floating-point minimum and maximum therefore should not be inferred from the generic names in this version. The proposed argument domain is integer types.

The history also records the addition of the unsequenced attribute to the interface description. Gustedt discusses the facilities as side-effect-free operations. That complements the concern about naive macros evaluating arguments repeatedly, but it should not be turned into an unrelated promise about evaluation order between arbitrary caller expressions.

The stdc_ prefix is another compatibility choice. The paper observes that min and max already appear widely as user identifiers, including variable names. A standard facility needs names that can be introduced without casually occupying those common spellings.

For a programmer, the central gain would be a specified answer to questions currently hidden inside local macro implementations. N3762 defines how promoted integer values compare and how the result type is selected. It also preserves integer constant expressions when both inputs have that property. Those requirements make the proposed interface useful in declarations as well as ordinary executable expressions.