Initial release. â¨
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 ( void *
) is the same size as any function pointer ( R ( * )( Args ...)
). 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 void *
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 void *
in an increased number of situations, to standardize existing practice.
The goal of this paper is to provide a single type, _Any_func
, through the core language. It is a core language type that is incomplete by itself, much like void
. Additionally, a pointer to _Any_func
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 void *
counterpart. It is modeled directly after void *
and modifies the same places in the wording, as well as a few other places.
Then, in noticing void *
on popular implementations has all these powers we are trying to give _Any_func *
here, we expanded the concept of void *
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 _Any_func *
and void *
as well as void *
and some_function_type *
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 int func ( int arg0 , double arg1 );
is not required to have the exact same calling convention, register allocation, and other important binary details as a KnR function int func2 ();
. Similarly, a function int func3 (...);
or int func4 ( int arg0 , ...);
is not required to have the same ABI details as either func
or func2
, 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 func
in a KnR function pointer int ( * )()
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 func2
and func3
, in particular when people would declare time_t time ()
as a KnR function on some platforms while competing with time_t time ( time_t * arg )
and similar definitions on various extern-and-exported-interface libraries.)
Not having _Any_func
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.
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 void *
-> some_function_type *
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 _Any_func *
and void *
, but void *
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:
__STDC_PTR_REPR_INCOMPATIBLE__
(value 0, "incompatible representation equivalence").
__STDC_PTR_REPR_CONVERTIBLE__
(value 1, "convertible representation equivalence" - what is guaranteed by basic C conformance today with void *
and object pointers).
__STDC_PTR_REPR_CORRESPONDING__
(value 2, "corresponding representation equivalence" - what Windows, POSIX:2018, etc. platforms guarantee but have to warn/error about in strictly-conforming C).
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:
__STDC_PTR_COMPAT_ANY_FUNC_AND_FUNC__
-- describes equivalence for _Any_func *
and all function pointer types; must be at least __STC_PTR_REPR_CONVERTIBLE__
(this proposal and matches void *
wit object pointers). Can be upgraded to __STDC_PTR_REPR_CORRESPONDING__
by an implementation.
__STDC_PTR_COMPAT_ANY_FUNC_AND_VOID__
-- describes equivalence between _Any_func *
and void *
; can be __STDC_PTR_REPR_INCOMPATIBLE__
.
__STDC_PTR_COMPAT_FUNC_AND_VOID__
-- describes equivalence between any function pointer and void *
; can be __STDC_PTR_REPR_INCOMPATIBLE__
.
__STDC_PTR_COMPAT_OBJECT_AND_VOID__
describes equivalence for all object pointers and void *
; must be at least __STC_PTR_REPR_CONVERTIBLE__
(guaranteed by wording in C standard currently). Can be upgraded to __STDC_PTR_REPR_CORRESPONDING__
by an implementation.
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: void *
to any object pointer (and back) always reports at least __STDC_PTR_REPR_CONVERTIBLE__
(a value of 1), and _Any_func *
to any function pointer (and back) always reports at least __STDC_PTR_REPR_CONVERTIBLE__
(a value of 1). However, conversion between void *
and _Any_func *
need not be supported (reports __STDC_PTR_REPR_INCOMPATIBLE__
(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 #error
inside of an #if
check if their code happens to any more advanced properties.
Finally, implementations that opt into having at least convertible representation equivalence for void *
and _Any_func *
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 void *
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.
The name chosen here is the one that had the no clashes in both its reserved form _Foo_bar
and itâs header form foo_bar
. The following other names were considered and searched for in public (and some private) code repositories for their prevalence as possible name candidates:
_Func_ptr_t
with func_ptr_t
(with no *
required for use)
_Any_func_ptr_t
with any_func_ptr_t
(with no *
required for use)
_Fn_ptr_t
with fn_ptr_t
(with no *
required for use)
_Fn
with fn
or stdc_fn
(user adds *
to make pointer)
_Func
with func
or std_func_t
(user adds *
to make pointer)
_Func_t
with func_t
or stdc_func_t
(user adds *
to make pointer)
Many of these had issues with existing standard library type names (e.g. _Fn
and _Func
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 ( fn_ptr_t
or fn
or func_t
). Other permutations of these names, including ones with _Storage_
/ _storage
or _Void
and _void
, either clashed with existing code or became undesirably long.
... ptr
In the Name or a Pointer to Incomplete Type?
The goal of this design was to feel as close to void *
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 void
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 void
" and " void *
" exist in the current standard. This eases integration and is -- after first explanation -- immediately understandable to those who have been using void *
as the omni-object pointer.
The library needs further modification to allow for passing this new pointer type in, since % p
by itself is specified to handle just void *
. Since function pointer types and void *
may not be the same size, a new entry is required to not taint the ABI of these functions, particularly of fprintf
and fscanf
. There is also discussion of uintptr_t
and intptr_t
; implementations may need additional integer types to handle this, and so these are provided under uintfuncptr_t
and intfuncptr_t
(and are as optional as their counterparts).
% 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, % lp
is already being used by CHERI, while % q
is already taken by typical POSIX shell-based printf
for quotable strings. To further disadvantage % q
, it -- despite being a logical new letter next to % p
-- is taken by BSD and still has some existing uses, even though the type itâs used for ( quad_t
) has long since been aliased to a "proper" type by now. Trying to sneak in % Lp
is awkward thanks to implementation already moving in on % lp
, especially if printing address spaces as part of pointers because a thing where length modifiers and precision get used to represent it. % Ip
seems nice for the mnemonic "instruction pointer", but i
is already a normal conversion specifier and I
is novel in this space as a modifier and a not a standalone conversion specifier.
Thusly, we settled for % jp
in this proposal. It can be read mnemonically as "jump pointer", which is reminiscent of assembly jmp
and for assembly junkies gives the feeling of both jmp
and call
. j
is also, already, a length modifier and has no known uses in the wild in combination with % p
. 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.
( 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, void ( * )( void )
is used as a generic catch-all function pointer storage type, but also has incrementing ability as part of its extension behavior. _Any_func *
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 char *
or unsigned char *
analogue for this like with void *
-- we have to employ the other means of address manipulation through a new integer type. ( u ) intfuncptr_t
is exactly like ( u ) intptr_t
, just with func
in the name. Itâs optional as well.
The _MAX
macros for this type are already taken care of by blanket specification. The only additional specification needed is for _WIDTH
, which is straightforward to write.
Finally, PRI ( i / u / U / x / X / b / B / o ) FUNCPTR
macros for printing and similar SCN ( i / u / x / b / o ) FUNCPTR
macros for scanning macros were added to the appropriate headers. This rounds out full library support for I/O with these numbers, mirroring uintptr_t
support.
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 void *
and most compilers in their / W4
, - Wall
, - pedantic
, or -- conformance
modes have been issuing errors for void *
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. WordingThe following wording is against the latest draft of the C standard.
5.1. Modify §6.2.5 "Types"5.2. Add a new section §6.2.6.3â¨"Pointer types" under §6.2.6 "Representation of types"...
...
The
_Any_func
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....
A pointer to
void
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_Any_func
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.
5.3. Modify §6.3.3.3 "Pointers"For certain pointer types, there are three levels of increasing
representation equivalencebetween 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__
,__STDC_PTR_REPR_CONVERTIBLE__
, and__STDC_PTR_REPR_CORRESPONDING__
(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.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
_Any_func
and pointers to function types characterizes the value of__STDC_PTR_COMPAT_ANY_FUNC_AND_FUNC__
;pointers to
_Any_func
and pointers tovoid
characterizes the value of__STDC_PTR_COMPAT_ANY_FUNC_AND_VOID__
;pointers to function types and pointers to
void
characterizes the value of__STDC_PTR_COMPAT_FUNC_AND_VOID__
; and,pointers to object types and pointers to
void
characterizes the value of__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
void *
may be required to ensure well-defined behavior on a hosted implementation:#include <stdio.h> int main () { struct toto* p = nullptr; printf("%p\n", (void*)p); // cast first to perform appropriate conversion return 0; }
5.4. Modify §6.4.2 "Keywords" to add a new keywordA pointer to
void
and a pointer to any object type shall have at least convertible representation equivalence (6.2.6.3â¨). A pointer tovoid
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....
An integer constant expression with the value
0
, such an expression cast to typevoid *
, such an expression cast to type_Any_func *
, or the predefined constantnullptr
is called a null pointer constant.57) If a null pointer constant or a value of the typenullptr_t
(which is necessarily the valuenullptr
) 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....
A pointer to
_Any_func
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.If a pointer to
_Any_func
and pointer tovoid
have at least convertible representation equivalence (6.2.6.3â¨), a pointer to_Any_func
can be converted to or from a pointer tovoid
. A pointer tovoid
can be converted to a pointer to_Any_func
and back again and vice-versa; the result shall compare equal to the original pointer.If a pointer to any function type and pointer to
void
have at least convertible representation equivalence (6.2.6.3â¨), a pointer tovoid
can be converted to or from a pointer to any function type. A pointer to any function type can be converted to a pointer tovoid
and back again and vice-versa; the result shall compare equal to the original pointer.
5.5. Modify §6.5.10 "Equality operators"Synopsis
keyword: one of
... â â â â â ... â â â â â ... â â â â â ... â â â â â
while
... â â â â â ... â â â â â ... â â â â â ... â â â â â
_Any_func
... â â â â â ... â â â â â ... â â â â â ... â â â â â
_Atomic
... â â â â â ... â â â â â ... â â â â â ... â â â â â ...
5.6. Modify §6.5.16 "Conditional operator"...
Constraints
One 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
void
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 ofvoid
;- if pointers to
_Any_func
and pointers tovoid
have at least convertible representation equivalence, one operand is a pointer to_Any_func
and the other is a pointer tovoid
;...
...
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
nullptr_t
, 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 ofvoid
, 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_Any_func
, the former is converted to the type of the latter. If pointers tovoid
and pointers to_Any_func
have at least convertible representation equivalence, one operand is a pointer to_Any_func
, and the other operand is a pointer to qualified or unqualifiedvoid
, the former is converted to the type of the latter. If pointers tovoid
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 unqualifiedvoid
, the former is converted to the type of the latter.
5.7. Modify §6.5.17.2 "Simple assignment"...
Constraints
...
One of the following shall hold: ...
... ; or
one 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
void
, one operand is a pointer to a function type and the other is a pointer to a qualified or unqualified version ofvoid
;- if pointer to
_Any_func
have at least convertible representation equivalence to a pointer tovoid
, one operand is a pointer to_Any_func
and the other is a pointer to a qualified or unqualified version ofvoid
; or- 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
nullptr_t
and the other is a pointer, the result type is the pointer type; if both the second and third operands havenullptr_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 ; otherwise, one operand is a pointer tovoid
or a qualified version ofvoid
, in which case the result type is a pointer to an appropriately qualified version ofvoid
. If one operand is a pointer to object type and the other is a pointer to qualified or unqualifiedvoid
, the result type is a pointer to an appropriately qualified version ofvoid
. If one operand is a pointer to function type and the other is a pointer to_Any_func
, 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 unqualifiedvoid
, and the types of both operands have at least convertible representation equivalence, the result type is a pointer to an appropriately qualifiedvoid
. If one operand is a pointer to_Any_func
, the other is a pointer to qualified or unqualifiedvoid
, and the types of both operands have at least convertible representation equivalence, the result type is a pointer to an appropriately qualifiedvoid
.
5.8. Modify §6.10.10.2 "Predefined macros"Constraints
One 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
void
, and the type pointed to by the left operand has all the qualifiers of the type pointed to by the right operand;- 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
_Any_func
, and the type pointed to by the left operand has all the qualifiers of the type pointed to by the right operand;- if a pointer to
_Any_func
has at least convertible representation equivalence to pointer tovoid
, and the left operand is atomic, qualified, or unqualified pointer to_Any_func
, and the other is a pointer to a qualified or unqualified version ofvoid
, and the type pointed to by the left operand has all the qualifiers of the type pointed to by the right operand;- if pointers to function types have at least convertible representation equivalence to pointer to
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 an function type, and the other is a pointer to a qualified or unqualified version ofvoid
, and the type pointed to by the left operand has all the qualifiers of the type pointed to by the right operand;...
5.9. Modify §7.8.2 "Macros for format specifiers"The following macro names shall be defined by the implementation:
... ...__STDC_PTR_COMPAT_ANY_FUNC_AND_FUNC__
One of__STDC_PTR_REPR_INCOMPATIBLE__
,__STDC_PTR_REPR_CONVERTIBLE__
, or__STDC_PTR_REPR_CORRESPONDING__
tied to the level of representation eqvuialence (6.2.6.3â¨) between_Any_func *
and all function pointer types (6.3.3.3).__STDC_PTR_COMPAT_ANY_FUNC_AND_VOID__
One of__STDC_PTR_REPR_INCOMPATIBLE__
,__STDC_PTR_REPR_CONVERTIBLE__
, or__STDC_PTR_REPR_CORRESPONDING__
tied to the level of representation eqvuialence (6.2.6.3â¨) between_Any_func *
andvoid *
(6.3.3.3).__STDC_PTR_COMPAT_FUNC_AND_VOID__
One of__STDC_PTR_REPR_INCOMPATIBLE__
,__STDC_PTR_REPR_CONVERTIBLE__
, or__STDC_PTR_REPR_CORRESPONDING__
tied to the level of representation eqvuialence (6.2.6.3â¨) between all function pointer types andvoid *
(6.3.3.3).__STDC_PTR_COMPAT_OBJECT_AND_VOID__
One of__STDC_PTR_REPR_INCOMPATIBLE__
,__STDC_PTR_REPR_CONVERTIBLE__
, or__STDC_PTR_REPR_CORRESPONDING__
tied to the level of representation eqvuialence (6.2.6.3â¨) between all object pointer types andvoid *
(6.3.3.3). ... ...__STDC_PTR_REPR_INCOMPATIBLE__
The integer literal0
, indicating incompatible representation equivalence (6.2.6.3â¨).__STDC_PTR_REPR_CONVERTIBLE__
The integer literal1
, indicating convertible representation equivalence (6.2.6.3â¨).__STDC_PTR_REPR_CORRESPONDING__
The integer literal2
, indicating corresponding representation equivalence (6.2.6.3â¨). ... ...
5.10. Modify §7.17.6 "Atomic integer types"...
The
fprintf
macros for signed integers are:
... â ... â ... â ... â
PRIdPTR
âPRIdFUNCPTR
... â ... â ... â ... â
PRIiPTR
âPRIiFUNCPTR
The
fprintf
macros for unsigned integers are:
... â ... â ... â ... â
PRIbPTR
âPRIbFUNCPTR
... â ... â ... â ... â
PRIoPTR
âPRIoFUNCPTR
... â ... â ... â ... â
PRIuPTR
âPRIuFUNCPTR
... â ... â ... â ... â
PRIxPTR
âPRIxFUNCPTR
... â ... â ... â ... â
PRIXPTR
âPRIXFUNCPTR
The following
fprintf
macros for unsigned integer types are optional:
... â ... â ... â ... â
PRIBPTR
âPRIBFUNCPTR
...
The
fscanf
macros for signed integers are
... â ... â ... â ... â
SCNdPTR
âSCNdFUNCPTR
... â ... â ... â ... â
SCNiPTR
âSCNiFUNCPTR
The
fscanf
macros for unsigned integers are:
... â ... â ... â ... â
SCNbPTR
âSCNbFUNCPTR
... â ... â ... â ... â
SCNoPTR
âSCNoFUNCPTR
... â ... â ... â ... â
SCNuPTR
âSCNuFUNCPTR
... â ... â ... â ... â
SCNxPTR
âSCNxFUNCPTR
5.11. Modify §7.23.2.5 "Integer types capable of holding object pointers"For 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 type Typename equivalency
Atomic typename Direct name ... ...atomic_uintfuncptr_t
_Atomic uintfuncptr_t
... ...
5.12. Modify §7.23.3.5 "Width of integer types capable of holding object pointer types"The following type designates a signed integer type, other than a bit-precise integer type, with the property that any valid pointer to
void
can be converted to this type, then converted back to pointer tovoid
, and the result will compare equal to the original pointer:intptr_tThe following type designates an unsigned integer type, other than a bit-precise integer type, with the property that any valid pointer to
void
can be converted to this type, then converted back to pointer tovoid
, and the result will compare equal to the original pointer:uintptr_tThe following type designates a signed integer type, other than a bit-precise integer type, with the property that any valid pointer to
_Any_func
can be converted to this type, then converted back to pointer to_Any_func
, and the result will compare equal to the original pointer:intfuncptr_tThe following type designates an unsigned integer type, other than a bit-precise integer type, with the property that any valid pointer to
_Any_func
can be converted to this type, then converted back to pointer to_Any_func
, and the result will compare equal to the original pointer:uintfuncptr_tThese types are optional.
5.13. Modify §7.24.6.2 "TheINTPTR_WIDTH exactly UINTPTR_WIDTH UINTPTR_WIDTH 16INTFUNCPTR_WIDTH exactly UINTFUNCPTR_WIDTH UINTFUNCPTR_WIDTH 8
fprintf
function"
5.13.1. NOTE: IDENTICAL CHANGES TOSynopsis
#include <stdio.h> int fprintf(FILE * restrict stream, const char * restrict format, ...);Description
...
The length modifiers and their meanings are:
... ...j
Specifies that a followingb
,B
,d
,i
,o
,u
,x
, orX
conversion specifier applies to anintmax_t
oruintmax_t
argument; that a followingp
conversion specifier applies to an_Any_func *
argument; or that a followingn
conversion specifier applies to a pointer to anintmax_t
argument. ... ...The conversion specifiers and their meanings are:
... ...p
The argument shall be a pointer tovoid
, a pointer to_Any_func
, 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. ... ...
fwprintf
! 5.13.2. NOTE: UPDATE ANNEX J UNDEFINED BEHAVIOR (Number 34)! 5.14. Modify §7.24.6.3 "The fscanf
function"
5.14.1. NOTE: IDENTICAL EDITS TOSynopsis
#include <stdio.h> int fscanf(FILE * restrict stream, const char * restrict format, ...);Description
...
The length modifiers and their meanings are:
... ...j
Specifies that a followingb
,d
,i
,o
,u
,x
,X
, orn
conversion specifier applies to an argument with type pointer tointmax_t
oruintmax_t
; or, a followingp
conversion specifier applies to an argument with type pointer to pointer of_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% p
or% jp
conversion of thefprintf
function. The corresponding argument shall be a pointer to a pointer of void ; or, with thej
length modifier, a pointer to pointer of_Any_func
. 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% p
or% jp
conversion is undefined. ... ...
fwscanf
! 5.14.2. NOTE: UPDATE ANNEX J UNDEFINED BEHAVIOR (Number 36)!
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4