Discussion:
Typedef reverse declarator as type specifier
(too old to reply)
s***@gmail.com
2017-03-24 11:53:18 UTC
Permalink
Raw Message
Suggestion add in 6.7.2:

type-specifier:

typedef-name
( typedef-reverse-declarator )


And at 6.7.8

reverse-declarator:

pointer-reverse-opt reverse-direct-declarator

reverse-direct-declarator:

identifier
( reverse-declarator )
reverse-direct-declarator [ assignment-expression ]
reverse-direct-declarator ( )
reverse-direct-declarator . identifier
reverse-direct-declarator -> identifier

pointer-reverse:

*
* pointer-reverse


Now the meaning of such a typedef reverse declarator used as a type-specifier will be obvious - it'll create an unevaluated expression using the operations, specified in the declarator, on a virtual object with a type equal to the one of the typedef name used. Then the type of this expression will be used as the actual type-specifier for the declaration. This syntax will work with type-names as well - you only will have to add the additional parentheses around the type specifier. Examples:

{
typedef int ta[4][4], f();

(ta[0]) *v; //OK object v of type int (*)[4]

(f()) v1; //OK object v1 of type int


v = ((ta[0]) *)v1; //cast from int to int (*)[4]

v1 = ( ( f() ) )v; //cast from int (*)[4] to int


typedef struct t { int m; float b; } t, *pt;

(t.m) x; //OK object x of type int

(pt->b) x1; //OK object x of type float

(*pt) x3; //OK object x of type struct t
}

Now if the identifier inside the reverse-direct-declarator is not declared as a typedef-name obviously this would not work since then then we'll be dealing with an expression-statement that is using undefined syntax (since a cast operator expects a type-name inside its initial parentheses):

{
int ta[4][4], f();

(ta[0]) *v; //UB

(f()) v1; //UB
}
s***@casperkitty.com
2017-03-24 22:51:39 UTC
Permalink
Raw Message
I think what you're after here is a means of getting the type of an
lvalue expression, for purposes of e.g. converting a pointer to such a
type. That would be a useful ability, but I don't like the proposed
syntax. Suppose, for example, that f() is a pointer to a function that
accepts one argument of type void* and returns void*. What should be
the meaning of "void *q = (f)(g)"? Should it convert g into a pointer
of the same type as f, and then store the resulting pointer in q, or
should it call function f with argument g and store its return value
into q?

An intrinsic which would take an lvalue expression and yield its type, and
which could be used in both declarations and casts, would seem more helpful
than an ability to use cast sequence with something that isn't a type.
Richard Damon
2017-03-25 10:53:51 UTC
Permalink
Raw Message
Post by s***@casperkitty.com
I think what you're after here is a means of getting the type of an
lvalue expression, for purposes of e.g. converting a pointer to such a
type. That would be a useful ability, but I don't like the proposed
syntax. Suppose, for example, that f() is a pointer to a function that
accepts one argument of type void* and returns void*. What should be
the meaning of "void *q = (f)(g)"? Should it convert g into a pointer
of the same type as f, and then store the resulting pointer in q, or
should it call function f with argument g and store its return value
into q?
An intrinsic which would take an lvalue expression and yield its type, and
which could be used in both declarations and casts, would seem more helpful
than an ability to use cast sequence with something that isn't a type.
If you look at their proposal, and the comments at the very end, they
are NOT converting an lvalue to a type, but starting from a type and
allowing you to get the type from some sub-piece of it (element of an
array, member of a struct, return value of a function call) and use that
type. They specifically refer to using a variable instead of a typename
to build the expression as UB (when I think they mean a constraint
violation).

They may have some use case for this, but personally, this isn't an
operation that I have seen much need for in C. Maybe it might come up
when writing generics.
s***@casperkitty.com
2017-03-25 20:48:53 UTC
Permalink
Raw Message
Post by Richard Damon
If you look at their proposal, and the comments at the very end, they
are NOT converting an lvalue to a type, but starting from a type and
allowing you to get the type from some sub-piece of it (element of an
array, member of a struct, return value of a function call) and use that
type. They specifically refer to using a variable instead of a typename
to build the expression as UB (when I think they mean a constraint
violation).
I gotcha. I was confused, and was trying to do my best to figure out what
was intended, and figured if I wrote what I thought it meant then someone
might explain it better.

Having a syntax to mean "some fictitious lvalue of a particular type, for
use with operators like sizeof or a future _Typeof, would seem to serve
the same purposes as this concept, but might be less confusing. It would
seem weird to know that an expression could be cast to a type related to
some aspect of a particular aggregate or function type, but not know what
the related type should be. Adding a means by which _Typeof could work
with types rather than just expressions would be helpful, but I'd say that
_Typeof is the more fundamental aspect. Once that's added, the functionality
sought here might be obtainable via something like:

(*_Typeof((structType)static.memberName))somePointer

to convert some pointer into a pointer to the type of structureType's member
memberName. Since reserved word "static" can't appear immediately following
a cast operator, using it to make a cast operator yield a dummy object should
not pose any ambiguity with any existing versions of C.
Jakob Bohm
2017-03-25 23:18:43 UTC
Permalink
Raw Message
Post by s***@casperkitty.com
Post by Richard Damon
If you look at their proposal, and the comments at the very end, they
are NOT converting an lvalue to a type, but starting from a type and
allowing you to get the type from some sub-piece of it (element of an
array, member of a struct, return value of a function call) and use that
type. They specifically refer to using a variable instead of a typename
to build the expression as UB (when I think they mean a constraint
violation).
I gotcha. I was confused, and was trying to do my best to figure out what
was intended, and figured if I wrote what I thought it meant then someone
might explain it better.
Having a syntax to mean "some fictitious lvalue of a particular type, for
use with operators like sizeof or a future _Typeof, would seem to serve
the same purposes as this concept, but might be less confusing. It would
seem weird to know that an expression could be cast to a type related to
some aspect of a particular aggregate or function type, but not know what
the related type should be. Adding a means by which _Typeof could work
with types rather than just expressions would be helpful, but I'd say that
_Typeof is the more fundamental aspect. Once that's added, the functionality
(*_Typeof((structType)static.memberName))somePointer
to convert some pointer into a pointer to the type of structureType's member
memberName. Since reserved word "static" can't appear immediately following
a cast operator, using it to make a cast operator yield a dummy object should
not pose any ambiguity with any existing versions of C.
Alternatively, simply bless the following idioms, which are accepted as
an extension by many existing implementations:

sizeof(((sometype*)NULL)->somefield.somemember)

((char*)(&(((sometype*)NULL)->somefield.somemember)) - (char*)(NULL))

The latter is a common macro implementation of offsetof()

Which leaves only the lack of a typeof operator.




Enjoy

Jakob
--
Jakob Bohm, CIO, Partner, WiseMo A/S. https://www.wisemo.com
Transformervej 29, 2860 Søborg, Denmark. Direct +45 31 13 16 10
This public discussion message is non-binding and may contain errors.
WiseMo - Remote Service Management for PCs, Phones and Embedded
Loading...