[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c

Static Assertions that are Expressions

Joel C. Salomon

7/15/2011 2:18:00 AM

TL;DR: Is there a construct in C that will work something vaguely like
C1x's _Static_assert, but which yields an expression?


In another forum, we're dealing with functions that can usefully be made
<tgmath.h>-like generic, but for which mixing types is meaningless. I
suggested that, given the prototypes

int totalorder(double x, double y);
int totalorderf(float x, float y);

we could use the C1x keyword _Generic to define a macro totalorder(x,y)
for which
* totalorder(1.0, 2.0) => (totalorder)(1.0, 2.0)
* totalorder(1.0f, 2.0f) => (totalorderf)(1.0f, 2.0f)
* totalorder(1.0, 2.0f) => compile error
* totalorder(1.0f, 2.0) => compile error

The most obvious method of yielding a compile error in C1x is
_Static_assert, so we tried this:

#define totalorder(x,y) \
_Generic((x), \
float: _Generic((y), \
float: totalorderf, \
double: _Static_assert(0, "type mismatch")), \
double: _Generic((y), \
float: _Static_assert(0, "type mismatch")), \
double: totalorder))((x),(y))

The trouble is that _Generic expands to an expression, which
_Static_assert is not. So, to recap my question, is there some sort of
legal expression I can use that will allow the "good" generic selection
to work while producing an error -- almost any error will do -- on the
"bad" paths?

Thanks,
--Joel
6 Answers

Jens

7/15/2011 8:19:00 AM

0

On 15 Jul., 04:17, "Joel C. Salomon" <joelcsalo...@gmail.com> wrote:
> TL;DR:  Is there a construct in C that will work something vaguely like
> C1x's _Static_assert, but which yields an expression?
>
> In another forum, we're dealing with functions that can usefully be made
> <tgmath.h>-like generic, but for which mixing types is meaningless.  I
> suggested that, given the prototypes
>
>         int totalorder(double x, double y);
>         int totalorderf(float x, float y);
>
> we could use the C1x keyword _Generic to define a macro totalorder(x,y)
> for which
> * totalorder(1.0, 2.0)   => (totalorder)(1.0, 2.0)
> * totalorder(1.0f, 2.0f) => (totalorderf)(1.0f, 2.0f)
> * totalorder(1.0, 2.0f)  => compile error
> * totalorder(1.0f, 2.0)  => compile error
>
> The most obvious method of yielding a compile error in C1x is
> _Static_assert, so we tried this:
>
> #define totalorder(x,y) \
>     _Generic((x),                                        \
>         float: _Generic((y),                             \
>             float: totalorderf,                          \
>             double: _Static_assert(0, "type mismatch")), \
>         double: _Generic((y),                            \
>             float: _Static_assert(0, "type mismatch")),  \
>             double: totalorder))((x),(y))
>
> The trouble is that _Generic expands to an expression, which
> _Static_assert is not.  So, to recap my question, is there some sort of
> legal expression I can use that will allow the "good" generic selection
> to work while producing an error -- almost any error will do -- on the
> "bad" paths?
>
> Thanks,
> --Joel

Jens

7/15/2011 8:21:00 AM

0

On 15 Jul., 04:17, "Joel C. Salomon" <joelcsalo...@gmail.com> wrote:
> TL;DR:  Is there a construct in C that will work something vaguely like
> C1x's _Static_assert, but which yields an expression?

sizeof(double[2*(EXP)-1]) should usually work well here.

Jens

Ben Bacarisse

7/15/2011 10:41:00 AM

0

"Joel C. Salomon" <joelcsalomon@gmail.com> writes:

> TL;DR: Is there a construct in C that will work something vaguely like
> C1x's _Static_assert, but which yields an expression?
>
> In another forum, we're dealing with functions that can usefully be made
> <tgmath.h>-like generic, but for which mixing types is meaningless. I
> suggested that, given the prototypes
>
> int totalorder(double x, double y);
> int totalorderf(float x, float y);
>
> we could use the C1x keyword _Generic to define a macro totalorder(x,y)
> for which
> * totalorder(1.0, 2.0) => (totalorder)(1.0, 2.0)
> * totalorder(1.0f, 2.0f) => (totalorderf)(1.0f, 2.0f)
> * totalorder(1.0, 2.0f) => compile error
> * totalorder(1.0f, 2.0) => compile error
>
> The most obvious method of yielding a compile error in C1x is
> _Static_assert, so we tried this:
>
> #define totalorder(x,y) \
> _Generic((x), \
> float: _Generic((y), \
> float: totalorderf, \
> double: _Static_assert(0, "type mismatch")), \
> double: _Generic((y), \
> float: _Static_assert(0, "type mismatch")), \
> double: totalorder))((x),(y))
>
> The trouble is that _Generic expands to an expression, which
> _Static_assert is not. So, to recap my question, is there some sort of
> legal expression I can use that will allow the "good" generic selection
> to work while producing an error -- almost any error will do -- on the
> "bad" paths?

I'll suggest another tack. Why not just remove the option of the "bad"
types in the inner _Generic expressions? A type for y that is not
compatible with the only listed option is a constraint violation so a
diagnostic is required.

--
Ben.

Ben Bacarisse

7/15/2011 11:18:00 AM

0

Jens <jens.gustedt@gmail.com> writes:

> On 15 Jul., 04:17, "Joel C. Salomon" <joelcsalo...@gmail.com> wrote:
>> TL;DR:  Is there a construct in C that will work something vaguely like
>> C1x's _Static_assert, but which yields an expression?
>
> sizeof(double[2*(EXP)-1]) should usually work well here.

The original had a constant expression of 0 so one could just write

sizeof (double[-1])

but it also means that this could be used:

(0 ? totalorder : totalorderf)

(with any expression at all in place of the 0). Because the two
pointers are not to compatible types a diagnostic is required. It's
likely to be more "user friendly" than a message about the size of an
array and it might even refer to the types of one or both of the
functions (though it doesn't in gcc but it does in clang).

However, you will probably get a diagnostic even when the types
in the _Generic expressions match. The "other" expressions in a
_Generic are not evaluated, but that does not mean the compiler won't
complain about them. In fact, I think the compiler must do so unless
there is something subtle in C1x that I've missed. I.e. using an
expression that is a constraint violation in any arm of a _Generic
expression is not going to be the solution. Just leaving off that "bad"
arm will work better as I suggested elsewhere.

--
Ben.

Joel C. Salomon

7/15/2011 3:17:00 PM

0

On 07/15/2011 06:40 AM, Ben Bacarisse wrote:
> "Joel C. Salomon" <joelcsalomon@gmail.com> writes:
>> In another forum, we're dealing with functions that can usefully be made
>> <tgmath.h>-like generic, but for which mixing types is meaningless. I
>> suggested that, given the prototypes
>>
>> int totalorder(double x, double y);
>> int totalorderf(float x, float y);
>>
>> we could use the C1x keyword _Generic to define a macro totalorder(x,y)
>> for which
>> * totalorder(1.0, 2.0) => (totalorder)(1.0, 2.0)
>> * totalorder(1.0f, 2.0f) => (totalorderf)(1.0f, 2.0f)
>> * totalorder(1.0, 2.0f) => compile error
>> * totalorder(1.0f, 2.0) => compile error
>>
>> The most obvious method of yielding a compile error in C1x is
>> _Static_assert, so we tried this:
>>
>> #define totalorder(x,y) \
>> _Generic((x), \
>> float: _Generic((y), \
>> float: totalorderf, \
>> double: _Static_assert(0, "type mismatch")), \
>> double: _Generic((y), \
>> float: _Static_assert(0, "type mismatch")), \
>> double: totalorder))((x),(y))
>>
>> The trouble is that _Generic expands to an expression, which
>> _Static_assert is not. So, to recap my question, is there some sort of
>> legal expression I can use that will allow the "good" generic selection
>> to work while producing an error -- almost any error will do -- on the
>> "bad" paths?
>
> I'll suggest another tack. Why not just remove the option of the "bad"
> types in the inner _Generic expressions? A type for y that is not
> compatible with the only listed option is a constraint violation so a
> diagnostic is required.

Because .... Hmm, are you suggesting something like

#define totalorder(x,y) \
_Generic((x), \
float: _Generic((y), float: totalorderf), \
double: _Generic((y), double: totalorder)) ((x),(y))

instead? That should catch usages like

totalorder(1.0f, 2.0)

but will it catch

totalorder(1.0, 2.0f)

as well?

Is there a compiler under which I can test this?

--Joel

Ben Bacarisse

7/15/2011 6:27:00 PM

0

"Joel C. Salomon" <joelcsalomon@gmail.com> writes:

> On 07/15/2011 06:40 AM, Ben Bacarisse wrote:
>> "Joel C. Salomon" <joelcsalomon@gmail.com> writes:
>>> In another forum, we're dealing with functions that can usefully be made
>>> <tgmath.h>-like generic, but for which mixing types is meaningless. I
>>> suggested that, given the prototypes
>>>
>>> int totalorder(double x, double y);
>>> int totalorderf(float x, float y);
>>>
>>> we could use the C1x keyword _Generic to define a macro totalorder(x,y)
>>> for which
>>> * totalorder(1.0, 2.0) => (totalorder)(1.0, 2.0)
>>> * totalorder(1.0f, 2.0f) => (totalorderf)(1.0f, 2.0f)
>>> * totalorder(1.0, 2.0f) => compile error
>>> * totalorder(1.0f, 2.0) => compile error
>>>
>>> The most obvious method of yielding a compile error in C1x is
>>> _Static_assert, so we tried this:
>>>
>>> #define totalorder(x,y) \
>>> _Generic((x), \
>>> float: _Generic((y), \
>>> float: totalorderf, \
>>> double: _Static_assert(0, "type mismatch")), \
>>> double: _Generic((y), \
>>> float: _Static_assert(0, "type mismatch")), \
>>> double: totalorder))((x),(y))
>>>
>>> The trouble is that _Generic expands to an expression, which
>>> _Static_assert is not. So, to recap my question, is there some sort of
>>> legal expression I can use that will allow the "good" generic selection
>>> to work while producing an error -- almost any error will do -- on the
>>> "bad" paths?
>>
>> I'll suggest another tack. Why not just remove the option of the "bad"
>> types in the inner _Generic expressions? A type for y that is not
>> compatible with the only listed option is a constraint violation so a
>> diagnostic is required.
>
> Because .... Hmm, are you suggesting something like
>
> #define totalorder(x,y) \
> _Generic((x), \
> float: _Generic((y), float: totalorderf), \
> double: _Generic((y), double: totalorder)) ((x),(y))
>
> instead?

Exactly.

> That should catch usages like
>
> totalorder(1.0f, 2.0)
>
> but will it catch
>
> totalorder(1.0, 2.0f)
>
> as well?

I don't see why not. In the second case, 1.0 is of type double and 2.0f
id not so the inner _Generic has be a constraint violation.

> Is there a compiler under which I can test this?

The online clang documentation talked about it but my installed version
does not seem to understand them.

--
Ben.