On 03/12/2014 07:39 AM, David Brown wrote:
On 11/03/14 17:56, Keith Thompson wrote:
I haven't made use of it myself, but I believe _Generic can be nested to
handle the types of more than one parameter.
Perhaps -- but I think the size of the code would be proportional to the
square of the number of types it handles, and it couldn't be portably
written to apply to extended integer types. Perhaps it could be
Extended integer types are non-portable anyway.
But code that is portable can make use of extended integer types, if
they come into play through standard typedefs such as size_t, int64_t,
sig_atomic_t, etc. Dealing with this possibility using _Generic() is
problematic, because "No two generic associations in the same generic
selection shall specify compatible types.".
OK, that clause makes it quite a lot harder. Perhaps the best way then
would be to include <stdint.h> and use types intN_t for _Generic -
the different sizes (assuming the platform supports them, of course)
will not be compatible with each other.
Are different standard integer types "compatible" if they are the same
As a practical matter (I'll get to issue of what the standard says
farther down), same size is insufficient to enable two types to be
compatible. They must also have the same representation and alignment
requirements, and must use the same mechanism when passed as a parameter
and when returned as the value of a function.
That would cover any integer types of the same size, on any sane
computer - but would normally rule out compatibility between floating
point and integer types of the same size, and probably also
compatibility between pointers and integers. That is all fair enough.
I've argued in the past that the standard guarantees compatibility for
certain pairs of types (which do not include "int" and "long"), but that
it does not prohibit other pairs of types from happening to be
compatible on particular implementations. I was told that the cases
where the standard specifies that two types are compatible are
exhaustive - no other pairs of types can be compatible. This is an
example of a more general rule when interpreting the standard: whenever
it provides a list of things for which something is true, that list is
exhaustive unless the standard explicitly says otherwise. I knew of that
rule, but find that argument less than compelling, because the
compatibility rules are not provided as a list, but as several
independent clauses in widely separated parts of the standard.
However, the official interpretation is that whenever a constraint
requires that two types be compatible, it is a violation of that
constraint, requiring a diagnostic, if the two types are not ones
explicitly specified as being compatible by the standard.
After issuing the required diagnostic, the implementation is free to
produce an executable anyway, and if you chose to execute the resulting
program it might behave in exactly the same fashion as would be
mandatory if the standard had specified that those two types were
compatible, and the implementation is free to document this as a fact.
However, the diagnostic message is still the only mandatory result of
translating such a program. The implementation's documentation cannot,
therefore, accurately describe this fact by saying "int and long int are
compatible"; it must use some other wording to describe that fact.
Thanks for that explanation. It is reassuring to know that the reason I
couldn't find a clear definition in the standard is that there is no
clear definition in the standard! It seems an odd omission, given how
often phrases like "compatible types" turn up in the standard.