Issue | Summary | Status |
---|---|---|
1000 | Structure type compatibility with flexible array members | Open |
1001 | Qualified rvalues from structure or union members | Open |
1002 | Type qualifiers in [*] in abstract declarators |
Open |
1003 | Linkage between library functions | Open |
1004 | Classification of scanf failures |
Open |
1005 | Annex D refers to option removed from UAX#31 in revision 39 | Open |
1006 | atomic_fetch operations and "address types" |
Open |
1007 | Implicitly unsigned bit-fields ambiguity | Open |
1008 | Bad constraint on attributes with tags | Open |
1009 | extern thread_local should not be an external definition |
Open |
1010 | Termination of the execution with threads | Open |
1011 | powr (negative, qNaN) |
Open |
1012 | Error returns from specific width length modifiers | Open |
1013 | Ambiguity of "same type" | Open |
Authors: Joseph Myers
Date: 2025-03-05
Status: Open
The definition of compatible type for structure types (C23 6.2.7) allows two structures to be compatible where one ends with a flexible array member and the other ends with a member with complete array type. (Before C23, this was an issue for structures in separate translation units; C23 makes it applicable within a single translation unit.)
struct s { int a; char b[]; } x;
void f()
{
struct s { int a; char b[2]; } y = {};
x = y; // OK, assignment between compatible types.
}
However, the definition of flexible array members explicitly anticipates that the offset of the flexible array member may be different from that of a member with complete array type ("the offset of the array shall remain that of the flexible array member, even if this would differ from that of the replacement array"), which is not consistent with the types being compatible. Furthermore, the rules for assignment (and likewise initialization and argument passing and function return) and conditional expressions are underspecified in this case; it is not clear what members would be copied when such a mixture of types is involved.
In C23 6.2.7 (Compatible type and composite type), after the first bullet point for compatibility for structure and union types, insert another bullet point:
- if one member of the pair is declared with a complete array type, the other is declared with a complete array type;
Authors: Joseph Myers
Date: 2025-03-06
Status: Open
Cross-references: 0423, 0481
C23 6.7.3.5 (Atomic type specifiers) says "The properties associated with atomic types are meaningful only for expressions that are lvalues." and, similarly, in 6.7.4.1 (Type qualifiers), "The properties associated with qualified types are meaningful only for expressions that are lvalues.". Not being meaningful, however, leaves open the possibility that an rvalue might nevertheless have such a type (with no semantic difference compared to having an unqualified type).
Before C11, it was never possible to observe whether an rvalue had a
qualified type. C11 introduced _Generic
with the potential to
observe more details of the types of rvalues, and C23 introduced
typeof
, and these features resulted in a series of changes to avoid
rvalues having qualified or atomic types or to avoid such types being
observable:
The resolution of issue 0423 said that casts convert to the unqualified version of the named type, and that function types always return the unqualified version of the return type named in the declaration or type name.
The resolution of issue 0481 then dealt with
_Generic
on lvalues by saying the type of the controlling
expression is taken "as if it had undergone an lvalue conversion,
array to pointer conversion, or function to pointer conversion".
This left more ambiguous the case of any remaining rvalues with
qualified type: does "as if it had undergone an lvalue conversion"
remove qualifiers from the type of a qualified rvalue?
N2726
removed the const
qualifier from _Complex_I
and _Imaginary_I
.
The resolution of C23 CD1 comment GB-065 extended the resolution of issue 0423 to use the non-atomic versions of atomic types.
In June 2024, Aaron Ballman pointed out in reflector message 26025 that it was still possible to have a qualified rvalue when accessing a qualified member of an rvalue structure or union (the result of a function call, assignment expression, conditional expression or comma expression with structure or union type), leading to a long discussion continuing through July and into August. In that discussion, Alex Celeste pointed out (message 26098) that qualifiers on array element types (which before C23 were not considered to be qualifiers on the array type) should still be preserved.
Consistency with the direction of the sequence of changes listed above
would indicate that qualifiers and _Atomic
should not be preserved
in other cases. That suggests the following would be valid.
struct s1 { const int i; } f1();
struct s2 { const int a[1]; } f2();
struct s1a { _Atomic int i; } f1a();
struct s2a { _Atomic int a[1]; } f2a();
extern int i;
extern const int a[1];
extern _Atomic int aa[1];
extern typeof(f1().i) i;
extern typeof(f2().a) a;
extern typeof(f1a().i) i;
extern typeof(f2a().a) aa;
static_assert(_Generic(f1().i, int: 1, default: 0));
static_assert(_Generic(f2().a, const int *: 1, default: 0));
static_assert(_Generic(f1a().i, int: 1, default: 0));
static_assert(_Generic(f2a().a, _Atomic int *: 1, default: 0));
In C23 6.5.3.4 (Structure and union members), insert at the end of the first Semantics paragraph:
If the first expression is not an lvalue and the designated member does not have array type, the result has the unqualified, non-atomic version of the type of the designated member.
[*]
in abstract declaratorsAuthors: Joseph Myers
Date: 2025-03-06
Status: Open
Cross-references: 0289
An array declarator can have the form (syntax in C23 6.7.7.1):
direct-declarator
[
type-qualifier-listopt*
]
but the corresponding abstract-declarator syntax in 6.7.8 omits the
type-qualifier-listopt. David Keaton stated in
reflector message
14798 that this
difference was not deliberate. The response to issue
0289 fixed such a difference in the case where an
assignment expression is involved, but did nothing about the [*]
case.
If abstract declarators have a more restrictive syntax than
declarators, that confuses both the rules about replacing an
expression at function prototype scope with *
, and the rule that
"If, in a parameter declaration, an identifier can be treated either
as a typedef name or as a parameter name, it shall be taken as a
typedef name.". It seems clear that the syntax should match in the
two cases.
In C23 6.7.8 (Type names), change the fourth option in the Syntax for array-abstract-declarator:
direct-abstract-declaratoropt
[
type-qualifier-listopt*
]
Authors: Joseph Myers
Date: 2025-03-07
Status: Open
Cross-references: 0078
C23 footnote 20, in 6.2.2 (Linkages of identifiers), says:
There is no linkage between different identifiers.
Is this footnote (not normative) referring only to linkage between identifiers defined by the user's program? Or is it also intended to say that there cannot be linkage between different library functions?
In practice, it is common that pointers to library functions with
compatible semantics may compare equal: that memcpy == memmove
, or
ldexp == scalbn
, for example. The response to C90 issue
0078 said that this is permitted. However, the footnote
in question was added in C99, which makes it less clear if that issue
response reflects the current intent.
It seems appropriate to amend both normative and non-normative text to make clear that it is OK for pointers to different library functions to compare equal.
In C23 7.1.2 (Standard headers), insert text as follows.
Any declaration of a library function shall have external linkage. Pointers to different library functions may compare equal where this is compatible with the semantics of those functions.FN)
FN)For example, it is possible that
memcpy == memmove
or thatldexp == scalbn
.
In C23 6.2.2 (Linkages of identifiers), amend footnote 20 as follows.
There is noThis document does not define any mechanism to establish linkage between different identifiers. As described in 7.1.2, it is possible that pointers to different library functions compare equal where that is compatible with the semantics of those functions.
scanf
failuresAuthors: Joseph Myers
Date: 2025-03-07
Status: Open
Cross-references: 1012
C23 7.23.6.3 (The fscanf
function) describes failures as follows:
Failures are described as input failures (due to the occurrence of an encoding error or the unavailability of input characters), or matching failures (due to inappropriate input).
Unsupported specific width length modifiers (for example, %w123d
if
there is no int123_t
or int_least123_t
type and w123
is not
implementation-defined to be supported anyway) are defined as error
conditions for both printf
and scanf
functions (rather than
undefined behavior). But is such an error an input failure or a
matching failure? Or is it some new kind of failure, requiring the
quoted dichotomy to be updated?
The same issue also applies for fwscanf
.
No specific change is proposed here to address this issue since appropriate wording would depend on direction from the committee on what kind of failure this should be.
Authors: Joseph Myers
Date: 2025-03-07
Status: Open
C23 D.2.2 (Restricted Format Characters) refers to an option UAX#31-R1a that appears to have been removed in revision 39 of UAX#31 (the current revision as of this writing is revision 41).
This subclause should thus be updated or removed. See reflector message 25125 for some relevant references. It would be best for our Unicode experts and C++ liaison to establish what fix is best and most compatible with C++, but in the absence of that I propose the obvious minimal change.
Remove C23 D.2.2 (Restricted Format Characters).
atomic_fetch
operations and "address types"Authors: Joseph Myers
Date: 2025-03-07
Status: Open
C23 7.17.7.6 (The atomic_fetch
and modify generic functions) says:
All these operations are applicable to an object of any atomic integer type other than
_Atomic bool
,atomic_bool
, or the atomic version of an enumeration with underlying typebool
.
and then later says:
For address types, the result may be an undefined address, but the operations otherwise have no undefined behavior.
The effect seems to be confused about whether pointer types should be included or not; the first quoted sentence clearly does not include them, but the second one seems to envisage that they might be included. It also has further problems:
Making the minimal change of removing the second quoted sentence, as suggested in C23 CD1 comment GB-196, did not receive consensus, but the wording is still defective in its present state so some change is needed to address that (either allowing pointer types and adjusting the wording to avoid using terminology that is not defined, or removing the problematic sentence if only integer types are to be allowed). A larger set of changes, mixing both normative and non-normative changes but including changes to allow pointer types here, was in N2389, which was discussed in Ithaca, October 2019.
Given the previous lack of consensus, no specific wording change is proposed here; committee direction would be needed before proposing specific changes to address this issue.
Authors: Joseph Myers
Date: 2025-03-11
Status: Open
Cross-references: 0315
There are several cases in which the rule that bit-fields declared
with types that are not explicitly signed
or unsigned
might be
treated as if either signed
or unsigned
had been specified leaves
ambiguity about exactly what is permitted. One such case dates back
to C90, and others have arisen over time as features have been added
to the standard (but they are all included together in this issue
report given how closely related they are).
In C23, the rule is specified in 6.7.3.1 (Type specifiers):
Each of the comma-separated multisets designates the same type, except that for bit-fields, it is implementation-defined whether the specifier
int
designates the same type assigned int
or the same type asunsigned int
.
Footnote 132, in 6.7.3.2 (Structure and union specifiers), explicitly notes that such a type might be produced from a typedef name or typeof specifiers:
As specified in 6.7.3, if the actual type specifier used is
int
or a typedef-name defined asint
, then it is implementation-defined whether the bit-field is signed or unsigned. This includes anint
type specifier produced using the typeof specifiers (6.7.3.6).
(It's not entirely clear that this inclusion of typedef names is adequately supported by the normative text, but that's not the subject of this issue report.)
The final response to issue 0315 said the
implementation-defined signedness also applied for other
implementation-defined declared types such as char
, short
, long
and long long
.
No specific wording is suggested to address the questions here, as direction from the committee is needed. For C2Y, my preference would be to follow C++14 and remove the option for bit-fields to be implicitly unsigned when the declared type is not unsigned, but that would need a separate paper and not be appropriate to apply to C23 (notwithstanding that C++ core issue 739 was considered a defect for C++). If that change were made for C2Y, it might then be appropriate to declare most of these cases explicitly unspecified for C23; if no such change is made for C2Y, further consideration should be given to specifying some of these cases explicitly.
Suppose the declared type of the bit-field is a typedef name defined
in a standard header and required to be a signed integer type. Must
that type also be signed as a bit-field, or might it be unsigned (for
example, plain int
)?
#include <stddef.h>
#include <stdint.h>
struct s1 {
ptrdiff_t b1a : 20;
int32_t b1b : 20;
};
Although ptrdiff_t
illustrates that this issue was present in C90,
it may be more likely to be encountered with types such as int32_t
.
If the option for bit-fields to be implicitly unsigned is not removed, it might be appropriate to require typedefs in standard headers that are required to be signed integer types to be signed as bit-field types as well.
C11 introduced the rule that typedef names can be redefined with the
same type in the same scope. But what if the type is only the same
outside of bit-fields? Is the type of the bit-field considered
explicitly signed when one definition uses signed
and another does
not?
typedef int T;
typedef signed int T;
struct s2 {
T b2 : 20;
};
In some cases, it seems clear whether a type from the typeof specifiers should be considered explicitly signed. For example, typeof specifiers applied to a type name do not introduce any issues, and if the typeof specifiers are applied to an expression referring to a single declaration, or to a cast, it seems clear whether the resulting type is explicitly signed.
int i;
signed int si;
struct s3a {
typeof (int) b3a : 20; // not explicitly signed
typeof (signed int) b3b : 20; // explicitly signed
typeof (i) b3c : 20; // not explicitly signed
typeof (si) b3d : 20; // explicitly signed
typeof ((int) si) b3e : 20; // not explicitly signed
typeof ((signed int) i) b3f : 20; // explicitly signed
};
In some other cases, it is less clear: where composite types are involved, or usual arithmetic conversions, for example.
int i;
signed int si;
extern int x;
extern signed int x;
struct s3b {
typeof (x) b3g : 20;
typeof (i + si) b3h : 20;
};
In some further cases, the type appears to be specified as not
explicitly signed (and so potentially unsigned as a bit-field) because
the standard says int
rather than signed int
, but may not have
been considering this issue.
signed short s;
struct s3c {
typeof (+s) b3i : 20; // integer promotions convert signed short to int
typeof (s == s) b3j : 20; // comparisons return int
typeof (0) b3k : 20; // this integer literal has type int
typeof (-1) b3l : 20; // negating an int literal leaves type int
};
Which of the above cases should be considered explicitly signed, and which should not?
Does the rule about implementation-defined signedness include
_BitInt
?
struct s4 {
_BitInt (32) b4 : 20; // may this be unsigned?
};
I think there is a reasonable case to answer "no" to this question
based only on the current wording, on the basis that the response to
issue 0315 was only concerned with implementation-defined bit-field
types, and support for _BitInt
types for bit-fields is not
implementation-defined.
If the answer to Question 4 is "yes", does the constraint disallowing
a type _BitInt(1)
apply before or after the reinterpretation as
unsigned for a bit-field?
struct s5 {
_BitInt (1) b5 : 1; // is this valid if _BitInt bit-fields are unsigned?
};
Authors: Joseph Myers
Date: 2025-03-11
Status: Open
C23 6.7.3.2 (Structure and union specifiers) contains a constraint:
An attribute specifier sequence shall not appear in a struct-or-union specifier without a member declaration list, except in a declaration of the form:
struct-or-union attribute-specifier-sequence identifier
;
C23 6.7.3.4 (Tags) contains a stricter constraint:
A type specifier of the form
struct-or-union attribute-specifier-sequenceopt identifier
shall not contain an attribute specifier sequence.
The latter constraint does not make sense; if such an attribute specifier sequence is not allowed, why is this case in the syntax for struct-or-union-specifier at all?
The stated intent given in drafting notes in N2335 was:
struct [[something]] x; /* valid */
void f(struct [[something]] s); /* invalid */
However, both those cases go through the syntax for type-specifier, so both would be invalid with the constraints as written.
I think the latter constraint is in fact not needed at all because everything relevant is covered in the first quoted constraint.
In C23 6.7.3.4 (Tags), remove the paragraph (including attached footnote):
A type specifier of the form
struct-or-union attribute-specifier-sequenceopt identifier
shall not contain an attribute specifier sequence.141)
141) As specified in 6.7.3.2, the type specifier can be followed by a;
or a member declaration list.
extern thread_local
should not be an external definitionAuthors: Joseph Myers
Date: 2025-03-12
Status: Open
The following issue was pointed out by Ori Bernstein in reflector message 25279.
C23 6.9.3 says:
If the declaration of an identifier for an object has file scope and an initializer, or has file scope and storage-class specifier
thread_local
, the declaration is an external definition for the identifier.
This fails to allow for the combination extern thread_local
, which
should not be an external definition.
In C23 6.9.3, amend the quoted paragraph as follows:
If the declaration of an identifier for an object has file scope and an initializer, or has file scope and storage-class specifier
thread_local
withoutextern
, the declaration is an external definition for the identifier.
Authors: Jens Gustedt
Date: 2025-03-13
Status: Open
In C23 there is still ambiguity concerning the termination of the
execution in the presence of threads, in particular if some threads
are detached and not joined during the execution. Here, the behavior
of thrd_exit
for the last thread is not sufficiently
clarified. C23 7.28.5.5 (The thrd_exit
function) p5 states
The program terminates normally after the last thread has been terminated. The behavior is as if the program called the
exit
function with the statusEXIT_SUCCESS
at thread termination time.
This text seems to indicate that the notion of happens-before extends
to the overall termination of all threads (thus a "last" thread), but
it leaves it unspecified whether or not the execution of the cleanup
code that is run on exit
(atexit
handlers, closure of streams and
similar) synchronizes with threads that have been detached.
Our observation of implementations seems to indicate that such a synchronization does indeed take place, it would be better to note this explicitly in the standard. We propose to change the above paragraph to the following:
The program terminates normally after the last thread has been terminated. The behavior is as if the
programend of the call tothrd_exit
of this last thread synchronized with all terminations of other threads of the execution and thereafter is called theexit
function with the statusEXIT_SUCCESS
at thread termination time.
powr
(negative, qNaN)Authors: Joseph Myers
Date: 2025-03-18
Status: Open
Annex F is unclear about whether powr
(x, qNaN) raises "invalid" for
negative x, though the intent seems to be that it should (as
indicated in reflector message
29708 and CFP message
3415).
C23 F.10.1 (Mathematics <math.h>
and <tgmath.h>
) says:
Functions with a NaN argument return a NaN result and raise no floating-point exception, except where explicitly stated otherwise.
C23 F.10.5.7 (The powr
functions) says:
powr
(x, y) returns a NaN and raises the "invalid" floating-point exception for x < 0.
This doesn't explicitly include the case where y is a NaN. By
contrast, F.10.5.8 (The rootn
functions) says:
rootn
(x, 0) returns a NaN and raises the "invalid" floating-point exception for all x (including NaN).
IEEE 754-2019 says in clause 9:
powr(x, y) signals the invalid operation exception for x < 0
and:
powr(x, qNaN) is qNaN for x ≥ 0
together with a more general statement:
Outside its domain an operation shall return a quiet NaN and signal the invalid operation exception.
This seems to indicate that "invalid" should be raised in this case.
In F.10.5.7 (The powr
functions), amend the seventh bullet point as
indicated.
powr
(x, y) returns a NaN and raises the "invalid" floating-point exception for x < 0 and all y (including NaN).
Authors: Joseph Myers
Date: 2025-03-18
Status: Open
Cross-references: 1004
Each function in the printf
and scanf
family has its own
Returns specification that describes error cases and corresponding
return values as well as the return value on success (the error cases
sometimes depend on the specific function from the family; for
example, some kinds of errors can only occur for the functions using
files, not those using strings).
When error cases were added to fprintf
, fscanf
, fwprintf
and
fwscanf
for unsupported specific width length modifiers, no
corresponding changes were made to the Returns specification for
the other functions in those families, so failing to give those other
functions a corresponding error case (and leaving them with implicit
undefined behavior in this case). It seems clear that all functions
in these families should have corresponding error handling.
This is related to but separate from issue 1004, which
concerns the classification of such errors from scanf
functions.
Also, the descriptions for printf
functions refer to "specified
width length modifier" but those for scanf
functions refer to
"specific width length modifier", with no apparent reason for the
inconsistent terminology.
All these changes are to the Returns specification of their respective functions, and all subclause numbers are in C23.
First, for consistency of terminology, make the following changes.
In 7.23.6.2 (The fprintf
function), change:
The
fprintf
function returns the number of characters transmitted, or a negative value if an output or encoding error occurred or if the implementation does not support aspecifiedspecific width length modifier.
In 7.31.2.2 (The fwprintf
function), change:
The
fwprintf
function returns the number of wide characters transmitted, or a negative value if an output or encoding error occurred or if the implementation does not support aspecifiedspecific width length modifier.
Then amend the other functions in these families as follows.
In each of 7.23.6.4 (The printf
function), 7.23.6.6 (The snprintf
function), 7.23.6.7 (The sprintf
function), 7.23.6.9 (The vfprintf
function), 7.23.6.11 (The vprintf
function), 7.23.6.13 (The
vsnprintf
function), 7.23.6.14 (The vsprintf
) function), 7.31.2.4
(The swprintf
function), 7.31.2.6 (The vfwprintf
function),
7.31.2.8 (The vswprintf
function), 7.31.2.10 (The vwprintf
function), 7.31.2.12 (The wprintf
function), K.3.5.4.7 (The
sprintf_s
function), K.3.5.4.14 (The vsprintf_s
function),
K.3.9.2.4 (The swprintf_s
function), and K.3.9.2.9 (The
vswprintf_s
function), change:
... encoding error occurred or if the implementation does not support a specific width length modifier ...
(Some of these functions also refer to output errors earlier in the
amended text; others, where the output is to a string rather than a
file, do not. In the case of swprintf
,vswprintf
, swprintf_s
,
and vswprintf_s
, the amended text is followed by another error case
in the same sentence; in the case of sprintf_s
, vsprintf_s
,
swprintf_s
, and vswprintf_s
, a description of the return value
appears after the amended text.)
In each of 7.23.6.5 (The scanf
function), 7.23.6.8 (The sscanf
function), 7.23.6.10 (The vfscanf
function), 7.23.6.12 (The vscanf
function), 7.23.6.15 (The vsscanf
function), 7.31.2.5 (The swscanf
function), 7.31.2.7 (The vfwscanf
function), 7.31.2.9 (The
vswscanf
function), 7.31.2.11 (The vwscanf
function), 7.31.2.13
(The wscanf
function), K.3.5.4.3 (The fscanf_s
function),
K.3.5.4.5 (The scanf_s
function), K.3.5.4.8 (The sscanf_s
function), K.3.5.4.10 (The vfscanf_s
function), K.3.5.4.12 (The
vscanf_s
function), K.3.5.4.15 (The vsscanf_s
function), K.3.9.2.2
(The fwscanf_s
function), K.3.9.2.5 (The swscanf_s
function),
K.3.9.2.7 (The vfwscanf_s
function), K.3.9.2.10 (The vswscanf_s
function), K.3.9.2.12 (The vwscanf_s
function), and K.3.9.2.14 (The
wscanf_s
function), change:
... in the event of an early matching failure or if the implementation does not support a specific width length modifier.
In each of K.3.5.4.2 (The fprintf_s
function), K.3.5.4.4 (The
printf_s
function), K.3.5.4.6 (The snprintf_s
function), K.3.5.4.9
(The vfprintf_s
function), K.3.5.4.11 (The vprintf_s
function),
K.3.5.4.13 (The vsnprintf_s
function), K.3.9.2.1 (The fwprintf_s
function), K.3.9.2.3 (The snwprintf_s
function), K.3.9.2.6 (The
vfwprintf_s
function), K.3.9.2.8 (The vsnwprintf_s
function),
K.3.9.2.11 (The vwprintf_s
function), and K.3.9.2.13 (The
wprintf_s
function), change:
... runtime-constraint violation occurred or if the implementation does not support a specific width length modifier.
Authors: Joseph Myers
Date: 2025-03-18
Status: Open
Most places in the standard requiring consistency of types in two declarations or expressions use the notion of "compatible type". Two places, however, require the types to be the "same type", not just compatible, so avoiding needing to merge information from separate declarations but encountering places where it is not clear what counts as the same type (a concept with no definition in the standard).
C23 6.7.1 (Declarations) says:
a typedef name can be redefined to denote the same type as it currently does, provided that type is not a variably modified type;
C23 6.7.3.4 (Tags) says:
Where two declarations that use the same tag declare the same type, they shall both use the same choice of
struct
,union
, orenum
. If two declarations of the same type have a member-declaration or enumerator-list, one shall not be nested within the other and both declarations shall fulfill all requirements of compatible types (6.2.7) with the additional requirement that corresponding members of structure or union types shall have the same (and not merely compatible) types.
No specific wording is suggested to address the ambiguities identified here; direction from the committee is needed on what the answers should be, and maybe on the overall approach to take to defining "same type" better.
Do function type attributes form part of the type for the purposes of "same type"?
typedef int T1(int);
typedef int T1(int) [[reproducible]];
Suggested answer: they form part of the type (so where implementations accept this example, that is a bug).
Are function types the same if one specified a parameter as a pointer, and another specified it as a function or array adjusted to a pointer, or if one specified a qualified type for a parameter and another specified an unqualified type?
typedef int T2A(int *);
typedef int T2A(int []);
typedef int T2B(int (*)());
typedef int T2B(int ());
typedef int T2C(int);
typedef int T2C(const int);
C23 6.7.7.4 (Function declarators) says:
In the determination of type compatibility and of a composite type, each parameter declared with function or array type is taken as having the adjusted type and each parameter declared with qualified type is taken as having the unqualified version of its declared type.
That wording does not refer to "same type", but it would seem rather confusing for the types before adjustment to affect "same type" when not affecting the function's type in other ways.
Suggested answer: those pairs of types are the same (but wording may need amending to make that clear).
Does the use of static
inside a parameter array declarator affect
the type for the purposes of "same type"?
typedef int T3(int [2]);
typedef int T3(int [static 2]);
Suggested answer: it should not affect the type, if the suggested answer to the previous question is followed.
Both the uses of the "same type" concept are in contexts where
variably modified types are disallowed, to avoid problems comparing
such types. However, in the presence of typeof
that does not in
fact suffice to prevent such comparison issues, because of variably
modified parameters in function definitions, which are not treated the
same as [*]
but also do not make the function type itself variably
modified. Which of the following are considered the same type?
void f4a(int m, char (*p)[m]) {}
void f4b(int n, char (*p)[n]) {}
void f4c(int n, char (*p)[(n)]) {}
void f4d(int t, char (*p)[t*1]) {}
void f4e(int t, char (*p)[t+1]) {}
typedef void T4(int, char (*)[*]);
typedef typeof(f4a) T4;
typedef typeof(f4b) T4;
typedef typeof(f4c) T4;
typedef typeof(f4d) T4;
typedef typeof(f4e) T4;
Suggested approach for resolving this: apply the adjustment to [*]
for the purposes of the function type even in the case of function
definitions (but without affecting the type of the parameters when
referenced inside the definition).
A similar issue applies when parameters are declared using a
block-scope typedef name for a variably modified type; the adjustment
to [*]
appears not to occur in that case either. Which of the
following are considered the same type?
void f(int a)
{
typedef int T[a];
typedef int U[a];
typedef void T5(T*);
typedef void T5(T*);
typedef void T5(U*);
}
Suggested approach for resolving this: apply the adjustment to [*]
to any VLA type referenced in a parameter type, including when it
comes from a typedef name, not just when it uses an array declarator.