Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

complex problem with gcc usage

45 views
Skip to first unread message

aotto1968

unread,
Nov 18, 2022, 12:18:09 PM11/18/22
to
Hi,

My problem is I want to write macro/function able to use different code depending on the pointer argument.

→ MkOBJ(pointer)

the pointer is from a "struct" and have to change the behavior if the field "pointer->super.obj" is available or not.
I like to use something like:

#define MkOBJ(ptr) ifexists(ptr->super.obj) ? ptr->super.obj : ptr

1) thee are structs with "super.obj" filed and pointers without "super.obj" field.
2) I want to use a SINGLE macro "MkOBJ" to work on both kind of pointers.
3) I know there is "typesize" "offsetof" "typeof" but where is the "ifexists" ?
4) I want to have a compile-time solution and no run-time "work-arount"


mfg


Kaz Kylheku

unread,
Nov 18, 2022, 3:03:56 PM11/18/22
to
The _Generic mechanism ("generic selection") in C11 might be able to do
this. It's a relatively recent C feature which provides essentially a
compile-time type switch/case to select different variants of code
(which have to be expressions) based on the type of an expression.

_Generic will not give you a solution whereby the pointer can be to any
structure type whatsoever which has a super.obj member; you have to
commit to specific types that are all named in the selection.

E.g. suppose you have "struct foo" and "struct bar" which have this
super.obj. I think it goes something like:

_Generic(pointer, // <-- expression used for type only
struct foo * : pointer->super.obj,
struct bar * : pointer->super.obj,
default : pointer)

If pointer is a struct foo * or struct bar *, then use the
expression pointer->super.obj. Otherwise the pointer expression.

--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal

Chris M. Thomasson

unread,
Nov 18, 2022, 3:10:52 PM11/18/22
to

aotto1968

unread,
Nov 19, 2022, 3:43:37 AM11/19/22
to

Hi,

the "_Generic feature looks good and I found a solution:

/// cast a \e known-object into an \RMkNs{ObjectS} reference
#define MkOBJ_R(x) (_Generic((x),struct MkObjectS *:(*x),default:((*(x)).super.obj)))
/// cast a \e known-object into an \RMkNs{ObjectS} pointer
#define MkOBJ(x) (&MkOBJ_R(x))

and now the next problem arrive, this will *NOT* compile with C++.
I compile my "C" also together with "C++" code into a C++ namespace with the C++ compiler…
(just using the C++ as an other "quality-check" and to NOT use an external "c" library etc…

but C++ say: Why can't I use _Generic in C++ code?
stackoverflow.com/questions/42496875/why-cant-i-use-generic-in-c-code

in C++ they mention to use "function-Overload" but this is a MACRO and the core problem is
→ the "default" in "_Generic" also work for FUTURE code but an Overload have to be defined
at compile-time.

Lew Pitcher

unread,
Nov 19, 2022, 9:39:51 AM11/19/22
to
On Sat, 19 Nov 2022 09:43:23 +0100, aotto1968 wrote:

> Hi,
>
> the "_Generic feature looks good and I found a solution:
>
> /// cast a \e known-object into an \RMkNs{ObjectS} reference #define
> MkOBJ_R(x) (_Generic((x),struct MkObjectS
> *:(*x),default:((*(x)).super.obj)))
> /// cast a \e known-object into an \RMkNs{ObjectS} pointer #define
> MkOBJ(x) (&MkOBJ_R(x))
>
> and now the next problem arrive, this will *NOT* compile with C++.
> I compile my "C" also together with "C++" code into a C++ namespace with
> the C++ compiler… (just using the C++ as an other "quality-check" and to
> NOT use an external "c" library etc…
>
> but C++ say: Why can't I use _Generic in C++ code?
> → stackoverflow.com/questions/42496875/why-cant-i-use-generic-in-c-code

As your stackoverflow reference said, C is a different language than C++.

C++ does not treat the "C subset" of it's language the same way C does.
Some differences are insignificant, others are not.

You've encountered one of the "not insignificant" differences between the
"C subset of C++" and "standard C".

The way to fix this is to stop using treating your C code as if it were
written in "C++ C subset" language, and instead treat it as if it were
"C, written in C".

--
Lew Pitcher
"In Skills, We Trust"

Kaz Kylheku

unread,
Nov 19, 2022, 11:13:43 AM11/19/22
to
On 2022-11-19, aotto1968 <aott...@t-online.de> wrote:
>
> Hi,
>
> the "_Generic feature looks good and I found a solution:
>
> /// cast a \e known-object into an \RMkNs{ObjectS} reference
> #define MkOBJ_R(x) (_Generic((x),struct MkObjectS *:(*x),default:((*(x)).super.obj)))
> /// cast a \e known-object into an \RMkNs{ObjectS} pointer
> #define MkOBJ(x) (&MkOBJ_R(x))
>
> and now the next problem arrive, this will *NOT* compile with C++.

It's not C++; _Generic is an invention of the ISO C committee, added to
C in the 2011 revision of the standard ("C11").

C and C++ are separately evolving languages. C++ adopts some newer
features from C, but at a relatively glacial pace.

> but C++ say: Why can't I use _Generic in C++ code?

Why can't speak Chinese when ordering in a Greek restaurant?

You need to do:

#ifdef __cpluspuls
#define MkOBJ(x) // .... insert C++ solution here ...
#else
// above _Generic solution
#endif

C++ has compile-time genericity in the form of templates (template
classes, template functions), and supports something called partial
specialization whereby a template can have a different body for
specific combinations of the parameters types.

My C++ is rusty at the moment, but it looks something like:

// Base template, providing default implementation:

template <typename T>
inline MkObjectS *MkOBJ_R(T *ptr)
{
return ptr->super.obj;
}

// Specialization to MkObjectS *
template <>
inline MkObjectS *MkOBJ_R<MkObjectS *>(MkObjectS *ptr)
{
return ptr;
}

Because of the existence of templates, it seems unlikely that C++ will
pick up _Generic. _Generic can be regarded as C's answer to a lack
of templates, for some common situations, like defining type-generic
math routines.

It seems like it might be possible to write some elaborate macros which
provide generic selection in some reasonably convenient syntax, and
which compile to either C11 _Generic or else to a bunch of template
functions.

Ideally the syntax might look like

TYPE_CASE(X, (A, B), (C, D), ...)

Then you just #include the header that gives you this elaborate
macro and use it in C11 or C++ code.

aotto1968

unread,
Nov 19, 2022, 1:19:53 PM11/19/22
to

This works for "C" and "C++" but I'll not use this, because…

/// cast a \e known-object into an \RMkNs{ObjectS} reference
#define MkOBJ_R(x) (*(x)).super.obj
/// cast a \e known-object into an \RMkNs{ObjectS} pointer
#define MkOBJ(x) ((sizeof(*(x)) == sizeof(struct MkObjectS)) ? ((MK_OBJ)(x)) : &(*(x)).super.obj)

1. it does NOT work for reference
2. require HARD cast for success → this break compile-time-type-safty
3. "sizeof" as indicator is to "slippy" because unequal types COULD still have same size (alignment-problem)

Kaz Kylheku

unread,
Nov 19, 2022, 4:43:02 PM11/19/22
to
On 2022-11-19, aotto1968 <aott...@t-online.de> wrote:
>
It could be used as a fallback for compiling with a C implementation
speaking a dialect before before C11 (no _Generic).

You just don't catch those errors when building that way; but if that's
not what you mainly develop with, it doesn't matter.

Andrey Tarasevich

unread,
Nov 19, 2022, 5:34:20 PM11/19/22
to
On 11/19/2022 12:43 AM, aotto1968 wrote:
>
> the "_Generic feature looks good and I found a solution:
>
>   /// cast a \e known-object into an \RMkNs{ObjectS} reference
>   #define   MkOBJ_R(x)        (_Generic((x),struct MkObjectS
> *:(*x),default:((*(x)).super.obj)))
>   /// cast a \e known-object into an \RMkNs{ObjectS} pointer
>   #define   MkOBJ(x)          (&MkOBJ_R(x))

How is this a solution, when it does not even remotely match the
original problem? How does this implement `ifexists(ptr->super.obj)`?

--
Best regards,
Andrey

aotto1968

unread,
Nov 20, 2022, 2:40:38 AM11/20/22
to
The "ifexists" solution is more general the "_Generic" is more special… but one think I discovered
is that (?:) (even if expression is constant) can not be used for "references" and type-safety is partly gone.
One goal was to stay typesafe this mean the real problem was:

#define MkOBJ(ptr)

1. if type is MkObjectS than choose pointer
2. if type is not MkObjectS choose pointer->super.obj
3. if pointer->super.obj does not exists or if pointer->super.obj is NOT from
type MkObjectS than throw an compile error

→ the "_Generic" is full typesafe


Kaz Kylheku

unread,
Nov 20, 2022, 10:09:25 AM11/20/22
to
Because aotto is imposing the rule/assuption that in fact
ifexists(ptr->super.obj) is true in the default case when the argument
is other than a certain type, that being "struct MkObjectS *".

That type is assumed not to have a "super.obj" field; it won't be
used even if it has one. Any other kind of argument to the macro must
be a pointer to a struct/union that does have "super.obj", because
the selected expression accesses such a member; if it doesn't, there
will be a diagnostic. That's where the "ifexists" test is effectively
being done.
0 new messages