1. Revision History
1.1. Revision 0 - May 27th, 2025
-
Initial release. ✨
2. Introduction & Motivation
The majority of the motivation is the same as it was 30 years ago, 20 years, and 10 years ago. In [n2230], Martin Sebor captured the core of the motivation:
... A void pointer is not convertible to a function pointer, and conversely, function pointers aren’t convertible to void. It is conceivable that an implementation may (and some, in fact, do) define function pointers to have a different size or representation than void, and such conversions could result in the corruption of the opriginal value.
However, C does not specify an analogous generic function pointer. Unlike object types, a pointer to a function of one type can be converted to a pointer to a function of any other type and back with no change. This is a useful guarantee that makes function pointers safely interchangeable (except to call a function, of course). At the same time, the absence of a generic function pointer analogous to void* has led to a proliferation of workarounds in applications, libraries, and implementations alike. ...
Popular distributions, operating systems, and platforms such as POSIX, Windows/NT, and many other platforms require that a data pointer (
) is the same size as any function pointer (
). But, for many other platforms, function pointers are not the same size as data pointers altogether, either because there are multiple data segments and the data pointers are larger or -- less common but still present -- because function pointers are larger than data pointers. Rather than try to force
to change to patch this hole (which would be a very fundamental ABI break on many platforms), this proposal focuses instead on following in [n2230]'s footsteps and proposing a (core language) type to satisfy this need properly. It then adds the concept of "equivalence" to allow for the use of
in an increased number of situations, to standardize existing practice.
3. Design
The goal of this paper is to provide a single type,
, through the core language. It is a core language type that is incomplete by itself, much like
. Additionally, a pointer to
has the requirement that it is large enough to hold any function pointer type, and is implicitly convertible from and to any such pointer type, much like its
counterpart. It is modeled directly after
and modifies the same places in the wording, as well as a few other places.
Then, in noticing
on popular implementations has all these powers we are trying to give
here, we expanded the concept of
to allow for a larger and wider variety of (implicit) conversions. Recognizing that all platforms may not have the ability to, we made conversions specifically between
and
as well as
and
optional.
Finally, library changes are made to follow along with all of the appropriate changes.
3.1. Is It Callable?
It is NOT callable.
KnR functions had a serious flaw where despite being usable as "omni" function pointer types (ignoring the issue of return values and potential mismatches there): KnR functions had a different ABI than
functions and were not required to have the same ABI as other function types. For example, a function
is not required to have the exact same calling convention, register allocation, and other important binary details as a KnR function
. Similarly, a function
or
is not required to have the same ABI details as either
or
, even under the circumstances that they were all called like so:
int a = 0 ; double b = 1 ; func ( a , b ); func2 ( a , b ); func3 ( a , b ); func4 ( a , b );
Storing
in a KnR function pointer
and then calling it as such was not required to work in any version of C (it’s explicitly undefined behavior in every version of C, see "6.3.3.3 Pointers" in the latest working draft and similar paragraphs in C23, C17, and further back). It just so happens that it did happen to work (though technically can and could fail in invisible-to-the-Abstract-Machine ways) for the vast majority of existing C code, due to how most ABIs tend to be designed. (There were ABI issues between
and
, in particular when people would declare
as a KnR function on some platforms while competing with
and similar definitions on various extern-and-exported-interface libraries.)
Not having
be callable avoids this problem entirely, by refusing to attach a binary representation that represents "all function calls". A cast must be inserted, and that prevents small usability errors. This does not mean that a omni-callable type should not exist. It’s just that there’s likely some form of small "shim" or "trampoline" that might need to be created in order to facilitate this correctly (or, in typical cases with most ABIs, just a raw copy). This is something that should be facilitated by a dedicated language ure for that express purpose, rather than something falling out of an accident of syntax.
3.2. Giving void *
Additional Powers
Furthermore, as this is defined in the core language, we can also provide a core language predefined macro for whether or not
->
and vice-versa is an allowable, legal translation. This also allows us to put wording in the core language that blesses such an (implicit) conversion, given that it’s highly prevalent on a wide variety of architectures. It is often seen as a "gotcha" that this conversion doesn’t work, and users have been asking for this change for a very long time. We obviously do not want to make things worse for embedded platforms or make them non-conforming; they are an important bedrock of C.
Therefore, we define a new concept "representation equivalence" so that we can support the notion of conversion not only between
and
, but
and any function pointer type. This also further helps us because we can specify properties beyond what is currently blessed by the C standard, and make allowances for the popular platforms which form the overwhelming super majority of platforms that developers work on, even in C:
-
(value 0, "incompatible representation equivalence").__STDC_PTR_REPR_INCOMPATIBLE__ -
(value 1, "convertible representation equivalence" - what is guaranteed by basic C conformance today with__STDC_PTR_REPR_CONVERTIBLE__
and object pointers).void * -
(value 2, "corresponding representation equivalence" - what Windows, POSIX:2018, etc. platforms guarantee but have to warn/error about in strictly-conforming C).__STDC_PTR_REPR_CORRESPONDING__
These predefined macros and their definitions are then applied to four new different predefined macros, which has one of the above 3 value macros as its definition:
-
-- describes equivalence for__STDC_PTR_COMPAT_ANY_FUNC_AND_FUNC__
and all function pointer types; must be at least_Any_func *
(this proposal and matches__STC_PTR_REPR_CONVERTIBLE__
wit object pointers). Can be upgraded tovoid *
by an implementation.__STDC_PTR_REPR_CORRESPONDING__ -
-- describes equivalence between__STDC_PTR_COMPAT_ANY_FUNC_AND_VOID__
and_Any_func *
; can bevoid *
.__STDC_PTR_REPR_INCOMPATIBLE__ -
-- describes equivalence between any function pointer and__STDC_PTR_COMPAT_FUNC_AND_VOID__
; can bevoid *
.__STDC_PTR_REPR_INCOMPATIBLE__ -
describes equivalence for all object pointers and__STDC_PTR_COMPAT_OBJECT_AND_VOID__
; must be at leastvoid *
(guaranteed by wording in C standard currently). Can be upgraded to__STC_PTR_REPR_CONVERTIBLE__
by an implementation.__STDC_PTR_REPR_CORRESPONDING__
Each implementation can support the level that is appropriate for their platform. Some basic support is already supported for 2 of the conversions, both as per this proposal and as per the original purpose of the type since 1989:
to any object pointer (and back) always reports at least
(a value of 1), and
to any function pointer (and back) always reports at least
(a value of 1). However, conversion between
and
need not be supported (reports
(a value of 0)), as that is not guaranteed to work on all platforms. This is useful for implementations that decide they do not want to take on an impossible task where object/data pointers and function/code points address completely different kinds of memory. Implementations that can not handle it (e.g. 16-bit Texas Instrument DSPs or 8-bit multi-address-space chips that have 21 bit function pointers but 16 bit memory addresses). Most modern implementations -- Windows/NT since forever and POSIX since the 90s with XSI extensions (and just simply required by POSIX 2018) -- would have this defined, and users could
inside of an
check if their code happens to any more advanced properties.
Finally, implementations that opt into having at least convertible representation equivalence for
and
should be able to use those types in conversions without constraint violations. Similarly, there is additional wording to allow for any function pointer type to work with (implicit) assignment to
or vice-versa if the representation equivalence is high enough. This standardizes existing practice, where many implementations do not warn or error on the constraint violation of for unrelated pointer types.
3.3. Naming
The name chosen here is the one that had the no clashes in both its reserved form
and it’s header form
. The following other names were considered and searched for in public (and some private) code repositories for their prevalence as possible name candidates:
-
with_Func_ptr_t
(with nofunc_ptr_t
required for use)* -
with_Any_func_ptr_t
(with noany_func_ptr_t
required for use)* -
with_Fn_ptr_t
(with nofn_ptr_t
required for use)* -
with_Fn
orfn
(user addsstdc_fn
to make pointer)* -
with_Func
orfunc
(user addsstd_func_t
to make pointer)* -
with_Func_t
orfunc_t
(user addsstdc_func_t
to make pointer)*
Many of these had issues with existing standard library type names (e.g.
and
for C++ type names in templates and typedefs for standard or standard-adjacent libraries) or had common names that, even if hidden behind a header include, would result in undue naming burden on potential downstream users (
or
or
). Other permutations of these names, including ones with
/
or
and
, either clashed with existing code or became undesirably long.
3.4. ... ptr
In the Name or a Pointer to Incomplete Type?
The goal of this design was to feel as close to
as possible, since that is what this type represents. This means that we wanted to have the
present to have it look and feel just like a regular pointer type under regular pointer rules, rather than having it be part of the name. Since this is a core language type and a not a library definition, we preferred to define it closer to
than anything else. It also helps in putting this type into the specification, as all we have to do is mirror exactly the specification style and places that "A pointer to
" and "
" exist in the current standard. This eases integration and is -- after first explanation -- immediately understandable to those who have been using
as the omni-object pointer.
3.5. Library Modifications
The library needs further modification to allow for passing this new pointer type in, since
by itself is specified to handle just
. Since function pointer types and
may not be the same size, a new entry is required to not taint the ABI of these functions, particularly of
and
. There is also discussion of
and
; implementations may need additional integer types to handle this, and so these are provided under
and
(and are as optional as their counterparts).
3.5.1. % jp
for fprintf
and fscanf
There were a bunch of potential candidates but a lot of them had problems both because of existing uses in implementations or down-stream, or they were novel new modifiers. For example,
is already being used by CHERI, while
is already taken by typical POSIX shell-based
for quotable strings. To further disadvantage
, it -- despite being a logical new letter next to
-- is taken by BSD and still has some existing uses, even though the type it’s used for (
) has long since been aliased to a "proper" type by now. Trying to sneak in
is awkward thanks to implementation already moving in on
, especially if printing address spaces as part of pointers because a thing where length modifiers and precision get used to represent it.
seems nice for the mnemonic "instruction pointer", but
is already a normal conversion specifier and
is novel in this space as a modifier and a not a standalone conversion specifier.
Thusly, we settled for
in this proposal. It can be read mnemonically as "jump pointer", which is reminiscent of assembly
and for assembly junkies gives the feeling of both
and
.
is also, already, a length modifier and has no known uses in the wild in combination with
. It is the best we can do given the Wild Wild West of specifiers and modifiers in the C-and-derivative ecosystem, at this point.
3.5.2. ( u ) intfuncptr_t
and printing/scanning macros
Given that we have a new pointer type for functions, individuals will want to manipulate the numeric representation of these pointers. The reason for this is simple: in the GCC extension,
is used as a generic catch-all function pointer storage type, but also has incrementing ability as part of its extension behavior.
does not have such powers, and it was not added to the Additive Operators in the wording. Thus, in order to appropriately manipulate such pointers -- while knowing that there is not
or
analogue for this like with
-- we have to employ the other means of address manipulation through a new integer type.
is exactly like
, just with
in the name. It’s optional as well.
The
macros for this type are already taken care of by blanket specification. The only additional specification needed is for
, which is straightforward to write.
Finally,
macros for printing and similar
macros for scanning macros were added to the appropriate headers. This rounds out full library support for I/O with these numbers, mirroring
support.
4. Existing Practice
This proposal does not change any existing implementation’s requirements or abilities. It is purely a formalization of existing practice that has existed both at the hardware and platform/ABI levels since time immemorial (at least 1972, by our estimate). Function pointer types have, for a long time, not been convertible to
and most compilers in their
,
,
, or
modes have been issuing errors for
and function pointer conversions but allowing it without warning or error in other cases. Several hardware and software platforms provide a unified data address space (Windows for some 31 years, POSIX with XSI since time immemorial/POSIX:2018, and many other platforms). The goal of this proposal is to solidify this existing practice into the C standard while still preserving the principles and practices of exotic hardware that still exists today: that is, DSPs and Microprocessors by exotic chipmakers and platform vendors (e.g., Texas Instruments) can still continue to vend chips with 16-bit data pointers and 23/24-bit function pointers (or otherwise) and typical Harvard Architectures can still be supported under this paradigm.
Therefore, this proposal makes no patches and provides no novel new compiler infrastructure, because all of this compiler infrastructure (a) already exists and (b) is already being taken advantage of by existing code.
5. Wording
The following wording is against the latest draft of the C standard.
5.1. Modify §6.2.5 "Types"
6.5.2Types...
...
The
type comprises the concept of a function; it is a function type unlike any other and has no return type and no parameter types. It cannot be called.
_Any_func ...
A pointer to
shall have the same representation and alignment requirements as a pointer to a character type.41) Similarly, pointers to qualified or unqualified versions of compatible types shall have the same representation and alignment requirements. A pointer to
void shall have an alignment and representation suitable for the storage of any function pointer type. All pointers to structure types shall have the same representation and alignment requirements as each other. All pointers to union types shall have the same representation and alignment requirements as each other. Pointers to other types may not have the same representation or alignment requirements.
_Any_func
5.2. Add a new section §6.2.6.3✨"Pointer types" under §6.2.6 "Representation of types"
6.2.6.3✨Pointer typesFor certain pointer types, there are three levels of increasing representation equivalence between them:
incompatible representation equivalence, where they do not have a common alignment and representation and cannot be converted to one another and back without preserving its value;
convertible representation equivalence, where they do not have a common alignment and representation but can be converted to one another and back with preserving its value; or,
correspoding representation equivalence, where they have a compatible alignment and representation.
This property is communicative in both conversion directions for the two pointer types. Each of these levels correspond to the predefined macros
,
__STDC_PTR_REPR_INCOMPATIBLE__ , and
__STDC_PTR_REPR_CONVERTIBLE__ (6.10.10.2), respectively. Representation equivalence can be compared against other representation equivalences; higher values subsume the permissions and properties of lower values, except for incompatible representation equivalence which has no permissions and provides no additional properties.
__STDC_PTR_REPR_CORRESPONDING__ Two pointer types with incompatible representation equivalences cannot be converted implicitly from one to another and back. An explicit conversion from a pointer of the first type to the second type and then back to the first type can possibly result in a pointer with a different representation that does not compare equal to the original.
Two pointer types with convertible representation equivalences can be converted implicitly or explicitly from one to another and back. A conversion, implicit or explicit, from a pointer of the first type to the second type and then back to the first type shall result in a pointer comparing equal to the the original. The alignment and representation of the first and second pointer types can possibly not be be equivalent or similar.
Two pointer types with corresponding representation equivalences have equivalent alignments and representations. A conversion, implicit or explicit, from a pointer of the first type to the second type shall result in two pointers whose object representations are identical.
NOTE 1 Typically, the byte array of two pointers that have corresponding representation equivalences compare equal after conversions, except for any padding bits which have unspecified values.
Outside of what is defined in 6.3.3.3 and 6.5, representation equivalence is implementation defined and any operations or conversions associated with such representation equivalences are conditionally supported. The representation equivalence between:
pointers to
and pointers to function types characterizes the value of
_Any_func ;
__STDC_PTR_COMPAT_ANY_FUNC_AND_FUNC__ pointers to
and pointers to
_Any_func characterizes the value of
void ;
__STDC_PTR_COMPAT_ANY_FUNC_AND_VOID__ pointers to function types and pointers to
characterizes the value of
void ; and,
__STDC_PTR_COMPAT_FUNC_AND_VOID__ pointers to object types and pointers to
characterizes the value of
void .
__STDC_PTR_COMPAT_OBJECT_AND_VOID__ NOTE 2 The file-scope declarations
static_assert ( __STDC_PTR_COMPAT_OBJECT_AND_VOID__ >= __STDC_PTR_REPR_CONVERTIBLE__ ); static_assert ( __STDC_PTR_COMPAT_ANY_FUNC_AND_FUNC__ >= __STDC_PTR_REPR_CONVERTIBLE__ ); do not provoke a constraint violation on any implementation. However, the following file scope declarations potentially trigger constraint violations on implementations:
// "Any_func *" may be incompatible to "void *", // and vice-versa static_assert ( __STDC_PTR_COMPAT_ANY_FUNC_AND_VOID__ != __STDC_PTR_REPR_INCOMPATIBLE__ ); // "void *" may be incompatible to one or more // function pointer types, and vice-versa static_assert ( __STDC_PTR_COMPAT_FUNC_AND_VOID__ != __STDC_PTR_REPR_INCOMPATIBLE__ ); EXAMPLE The following program potentially exhibits undefined behavior without corresponding representation equivalence:
#include <stdarg.h>struct toto * p = nullptr ; int f (...) { va_list ap ; va_start ( ap ); void * arg = va_arg ( ap , void * ); // possible undefined behavior if ( arg == p ) { // this code might not be reached. va_end ( ap ); return 0 ; } va_end ( ap ); return 1 ; } int main () { return f ( p ); // not guaranteed to return 0 } More practically, on a hosted implementation, the following program potentially needs corresponding representation equivalence to print with the expected implementation-defined behavior:
#include <stdio.h>int main () { static_assert ( __STDC_PTR_COMPAT_OBJECT_AND_VOID__ == __STDC_PTR_REPR_CORRESPONDING__ , "Corresponding representation equivalence is required." ); struct toto * p = nullptr ; printf ( "%p \n " , p ); return 0 ; } Otherwise, a cast to
may be required to ensure well-defined behavior on a hosted implementation:
void * #include <stdio.h>int main () { struct toto * p = nullptr ; printf ( "%p \n " , ( void * ) p ); // cast first to perform appropriate conversion return 0 ; }
5.3. Modify §6.3.3.3 "Pointers"
6.3.3.3PointersA pointer toand a pointer to any object type shall have at least convertible representation equivalence (6.2.6.3✨). A pointer to
void can be converted to or from a pointer to any object type. A pointer to any object type can be converted to a pointer to void and back again; the result shall compare equal to the original pointer.
void ...An integer constant expression with the value
, such an expression cast to type
0 , such an expression cast to type
void * , or the predefined constant
_Any_func * is called a null pointer constant.57) If a null pointer constant or a value of the type
nullptr (which is necessarily the value
nullptr_t ) is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.
nullptr ...A pointer to
and a pointer to any other function type shall have at least convertible representation equivalence (6.2.6.3✨). A pointer to any function type can be converted to a pointer to
_Any_func and back again and vice-versa; the result shall compare equal to the original pointer.
_Any_func If a pointer to
and pointer to
_Any_func have at least convertible representation equivalence (6.2.6.3✨), a pointer to
void can be converted to or from a pointer to
_Any_func . A pointer to
void can be converted to a pointer to
void and back again and vice-versa; the result shall compare equal to the original pointer.
_Any_func If a pointer to any function type and pointer to
have at least convertible representation equivalence (6.2.6.3✨), a pointer to
void can be converted to or from a pointer to any function type. A pointer to any function type can be converted to a pointer to
void and back again and vice-versa; the result shall compare equal to the original pointer.
void
5.4. Modify §6.4.2 "Keywords" to add a new keyword
6.4.2KeywordsSynopsiskeyword: one of
... ... ... ...
while ... ... ... ...
_Any_func ... ... ... ...
_Atomic ... ... ... ... ...
5.5. Modify §6.5.10 "Equality operators"
6.5.10Equality operators...ConstraintsOne of the following shall hold: ...
...
one operand is a pointer to an object type and the other is a pointer to a qualified or unqualified version of
;
void - one operand is a pointer to a function type and the other is a pointer to
;
_Any_func - if pointers to function types and pointers to
have at least convertible representation equivalence, one operand is a pointer to a function type and the other is a pointer to a qualified or unqualified version of
void ;
void - if pointers to
and pointers to
_Any_func have at least convertible representation equivalence, one operand is a pointer to
void and the other is a pointer to
_Any_func ;
void ...
...Otherwise, at least one operand is a pointer. If one operand is a pointer and the other is a null pointer constant or has type
, they compare equal if the former is a null pointer. If one operand is a pointer to an object type and the other is a pointer to a qualified or unqualified version of
nullptr_t , the former is converted to the type of the latter. If one operand is a pointer to a function type and the other is a pointer to
void , the former is converted to the type of the latter. If pointers to
_Any_func and pointers to
void have at least convertible representation equivalence, one operand is a pointer to
_Any_func , and the other operand is a pointer to qualified or unqualified
_Any_func , the former is converted to the type of the latter. If pointers to
void and pointers to function types have at least convertible representation equivalence, one operand is a pointer to function type, and the other operand is a pointer to qualified or unqualified
void , the former is converted to the type of the latter.
void
5.6. Modify §6.5.16 "Conditional operator"
6.5.16Conditional operator...Constraints...One of the following shall hold: ...
...
; orone operand is a pointer to an object type and the other is a pointer to a qualified or unqualified version of
void .;- if pointer to function types have at least convertible representation equivalence to a pointer to
, one operand is a pointer to a function type and the other is a pointer to a qualified or unqualified version of
void ;
void - if pointer to
have at least convertible representation equivalence to a pointer to
_Any_func , one operand is a pointer to
void and the other is a pointer to a qualified or unqualified version of
_Any_func ; or
void - one operand is a pointer to a function type and the other is a pointer to
.
_Any_func ...If both the second and third operands are pointers, the result type is a pointer to a type qualified with all the type qualifiers of the types referenced by both operands; if one is a null pointer constant (other than a pointer) or has type
and the other is a pointer, the result type is the pointer type; if both the second and third operands have
nullptr_t type, the result also has that type. Furthermore, if both operands are pointers to compatible types or to differently qualified versions of compatible types, the result type is a pointer to an appropriately qualified version of the composite type; if one operand is a null pointer constant, the result has the type of the other operand
nullptr_t ; otherwise, one operand is a pointer to. If one operand is a pointer to object type and the other is a pointer to qualified or unqualifiedor a qualified version of
void , in which case the result type is a pointer to an appropriately qualified version of
void
void , the result type is a pointer to an appropriately qualified version of
void . If one operand is a pointer to function type and the other is a pointer to
void , the result type is a pointer to
_Any_func . If one operand is a pointer to function type, the other is a pointer to qualified or unqualified
_Any_func , and the types of both operands have at least convertible representation equivalence, the result type is a pointer to an appropriately qualified
void . If one operand is a pointer to
void , the other is a pointer to qualified or unqualified
_Any_func , and the types of both operands have at least convertible representation equivalence, the result type is a pointer to an appropriately qualified
void .
void
5.7. Modify §6.5.17.2 "Simple assignment"
6.5.17.2Simple assignmentConstraintsOne of the following shall hold: ...
...
the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) one operand is a pointer to an object type, and the other is a pointer to a qualified or unqualified version of
, and the type pointed to by the left operand has all the qualifiers of the type pointed to by the right operand;
void - the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) one operand is a pointer to a function type, and the other is a pointer to a qualified or unqualified version of
, and the type pointed to by the left operand has all the qualifiers of the type pointed to by the right operand;
_Any_func - if a pointer to
has at least convertible representation equivalence to pointer to
_Any_func , and the left operand is atomic, qualified, or unqualified pointer to
void , and the other is a pointer to a qualified or unqualified version of
_Any_func , and the type pointed to by the left operand has all the qualifiers of the type pointed to by the right operand;
void - if pointers to function types have at least convertible representation equivalence to pointer to
, the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) one operand is a pointer to an function type, and the other is a pointer to a qualified or unqualified version of
void , and the type pointed to by the left operand has all the qualifiers of the type pointed to by the right operand;
void ...
5.8. Modify §6.10.10.2 "Predefined macros"
6.10.10.2Predefined macrosThe following macro names shall be defined by the implementation:
... ...
__STDC_PTR_COMPAT_ANY_FUNC_AND_FUNC__ One of ,
__STDC_PTR_REPR_INCOMPATIBLE__ , or
__STDC_PTR_REPR_CONVERTIBLE__ tied to the level of representation eqvuialence (6.2.6.3✨) between
__STDC_PTR_REPR_CORRESPONDING__ and all function pointer types (6.3.3.3).
_Any_func *
__STDC_PTR_COMPAT_ANY_FUNC_AND_VOID__ One of ,
__STDC_PTR_REPR_INCOMPATIBLE__ , or
__STDC_PTR_REPR_CONVERTIBLE__ tied to the level of representation eqvuialence (6.2.6.3✨) between
__STDC_PTR_REPR_CORRESPONDING__ and
_Any_func * (6.3.3.3).
void *
__STDC_PTR_COMPAT_FUNC_AND_VOID__ One of ,
__STDC_PTR_REPR_INCOMPATIBLE__ , or
__STDC_PTR_REPR_CONVERTIBLE__ tied to the level of representation eqvuialence (6.2.6.3✨) between all function pointer types and
__STDC_PTR_REPR_CORRESPONDING__ (6.3.3.3).
void *
__STDC_PTR_COMPAT_OBJECT_AND_VOID__ One of ,
__STDC_PTR_REPR_INCOMPATIBLE__ , or
__STDC_PTR_REPR_CONVERTIBLE__ tied to the level of representation eqvuialence (6.2.6.3✨) between all object pointer types and
__STDC_PTR_REPR_CORRESPONDING__ (6.3.3.3).
void * ... ...
__STDC_PTR_REPR_INCOMPATIBLE__ The integer literal , indicating incompatible representation equivalence (6.2.6.3✨).
0
__STDC_PTR_REPR_CONVERTIBLE__ The integer literal , indicating convertible representation equivalence (6.2.6.3✨).
1
__STDC_PTR_REPR_CORRESPONDING__ The integer literal , indicating corresponding representation equivalence (6.2.6.3✨).
2 ... ...
5.9. Modify §7.8.2 "Macros for format specifiers"
7.8.2Macros for format specifiers...
The
macros for signed integers are:
fprintf
... ... ... ...
PRIdPTR
PRIdFUNCPTR ... ... ... ...
PRIiPTR
PRIiFUNCPTR The
macros for unsigned integers are:
fprintf
... ... ... ...
PRIbPTR
PRIbFUNCPTR ... ... ... ...
PRIoPTR
PRIoFUNCPTR ... ... ... ...
PRIuPTR
PRIuFUNCPTR ... ... ... ...
PRIxPTR
PRIxFUNCPTR ... ... ... ...
PRIXPTR
PRIXFUNCPTR The following
macros for unsigned integer types are optional:
fprintf
... ... ... ...
PRIBPTR
PRIBFUNCPTR ...
The
macros for signed integers are
fscanf
... ... ... ...
SCNdPTR
SCNdFUNCPTR ... ... ... ...
SCNiPTR
SCNiFUNCPTR The
macros for unsigned integers are:
fscanf
... ... ... ...
SCNbPTR
SCNbFUNCPTR ... ... ... ...
SCNoPTR
SCNoFUNCPTR ... ... ... ...
SCNuPTR
SCNuFUNCPTR ... ... ... ...
SCNxPTR
SCNxFUNCPTR
5.10. Modify §7.17.6 "Atomic integer types"
7.17.6Atomic integer typesFor each line in Table 7.6,307) the atomic type name is declared as a type that has the same representation and alignment requirements as the corresponding direct type.308)
Table 7.6 — Atomic typeTypename equivalency
Atomic typename Direct name ... ...
atomic_uintfuncptr_t
_Atomic uintfuncptr_t ... ...
5.11. Modify §7.23.2.5 "Integer types capable of holding object pointers"
7.23.2.5Integer types capable of holding object pointersThe following type designates a signed integer type, other than a bit-precise integer type, with the property that any valid pointer to
can be converted to this type, then converted back to pointer to
void , and the result will compare equal to the original pointer:
void intptr_t The following type designates an unsigned integer type, other than a bit-precise integer type, with the property that any valid pointer to
can be converted to this type, then converted back to pointer to
void , and the result will compare equal to the original pointer:
void uintptr_t The following type designates a signed integer type, other than a bit-precise integer type, with the property that any valid pointer to
can be converted to this type, then converted back to pointer to
_Any_func , and the result will compare equal to the original pointer:
_Any_func intfuncptr_t The following type designates an unsigned integer type, other than a bit-precise integer type, with the property that any valid pointer to
can be converted to this type, then converted back to pointer to
_Any_func , and the result will compare equal to the original pointer:
_Any_func uintfuncptr_t These types are optional.
5.12. Modify §7.23.3.5 "Width of integer types capable of holding object pointer types"
7.23.3.5Width of integer types capable of holdingobjectpointer typesINTPTR_WIDTH exactly UINTPTR_WIDTH UINTPTR_WIDTH 16 INTFUNCPTR_WIDTH exactly UINTFUNCPTR_WIDTH UINTFUNCPTR_WIDTH 8
5.13. Modify §7.24.6.2 "The fprintf
function"
7.24.6.2Thefunction
fprintf Synopsis#include <stdio.h>int fprintf ( FILE * restrict stream , const char * restrict format , ...); Description...
The length modifiers and their meanings are:
... ...
j Specifies that a following ,
b ,
B ,
d ,
i ,
o ,
u , or
x conversion specifier applies to an
X or
intmax_t argument; that a following
uintmax_t conversion specifier applies to an
p argument; or that a following
_Any_func * conversion specifier applies to a pointer to an
n argument.
intmax_t ... ... The conversion specifiers and their meanings are:
... ...
p The argument shall be a pointer to , a pointer to
void , or a pointer to a character type. The value of the pointer is converted to a sequence of printing characters, in an implementation-defined manner.
_Any_func ... ...
5.13.1. NOTE: IDENTICAL CHANGES TO fwprintf
!
5.13.2. NOTE: UPDATE ANNEX J UNDEFINED BEHAVIOR (Number 34)!
5.14. Modify §7.24.6.3 "The fscanf
function"
7.24.6.3Thefunction
fscanf Synopsis#include <stdio.h>int fscanf ( FILE * restrict stream , const char * restrict format , ...); Description...
The length modifiers and their meanings are:
... ...
j Specifies that a following ,
b ,
d ,
i ,
o ,
u ,
x , or
X conversion specifier applies to an argument with type pointer to
n or
intmax_t ; or, a following
uintmax_t conversion specifier applies to an argument with type pointer to pointer of
p .
_Any_func ... ... In the following, the type of the corresponding argument for a conversion specifier shall be a pointer to a type determined by the length modifiers, if any, or specified by the conversion specifier. The conversion specifiers and their meanings are:
... ...
p Matches an implementation-defined set of sequences, which should be the same as the set of sequences that may be produced by the or
% p conversion of the
% jp function. The corresponding argument shall be a pointer to a pointer of void ; or, with the
fprintf length modifier, a pointer to pointer of
j . The input item is converted to a pointer value in an implementation-defined manner. If the input item is a value converted earlier during the same program execution, the pointer that results shall compare equal to that value; otherwise the behavior of the
_Any_func or
% p conversion is undefined.
% jp ... ...