NO

Author Topic: _Generic is not standard compliant with C11 (Pelles C 7 and v8 RC2)  (Read 4533 times)

aMarCruz

  • Guest
Try this please.
This code don't compile (fail with error 2502: Multiple associations for type ... etc)

Code: [Select]
// generic_test.c
#include <stdio.h>
#pragma warn(disable:2096)

typedef struct tag_Point {
int X;
int Y;
} Point;
typedef struct tag_Size {
int Width;
int Height;
} Size;

#define GetType(T) _Generic((T), \
        Size*:IsSize, const Size*:IsSize, const Size *const:IsSize, Size *const:IsSize, \
        default: IsPoint)(T)

const char* IsSize(const Size *const sz) {
return "Size";
}
const char* IsPoint(const Point *const pt) {
return "Point";
}

int __cdecl main(void)
{
Size  sz = {10, 11};
const Size *s2 = &sz;
Size *const s3 = &sz;
const Size *const s4 = &sz;

printf("s2 type: %s\n", GetType(s2));
printf("s3 type: %s\n", GetType(s3));
printf("s4 type: %s\n", GetType(s4));

return 0;
}

nor using this define:

Code: [Select]
#define GetType(T) _Generic(*(T), \
        Size:IsSize, const Size:IsSize, \
        default: IsPoint)(T)

"const T" is not compatible with "T".
This compiles w/o warnings in clang 3.4 and clang-cl (MSVC mode), and mingw 4.8.1.

SO: Win7 32bits
Compiler: Pelles C v7 and 8 RC2.
Command line: pocc generic_test.c

excuse my "spanglish" :(
thanks.

@beto

aMarCruz

  • Guest
Re: _Generic is not standard compliant with C11 (Pelles C 7 and v8 RC2)
« Reply #1 on: April 18, 2014, 07:43:52 PM »
(Sorry, I was wrong. I have Clang in mingw mode,  mingw 4.8.1 is not working with _Generic).

An workaround is something like...

Code: [Select]
#ifdef __POCC__
# define GPPP_GEN_PTR_FNC(ptr,fnc) ptr*:fnc, const ptr*:fnc, ptr*const:fnc
# define GPPP_GEN_VAR_FNC(var,fnc) var:fnc
#else
# define GPPP_GEN_PTR_FNC(ptr,fnc) ptr*:fnc, const ptr*:fnc, ptr*const:fnc, const ptr*const:fnc
# define GPPP_GEN_VAR_FNC(var,fnc) var:fnc, const var:fnc
#endif

#define GEN_VAR_TYPE_NAME(T) GPPP_GEN_VAR_FNC(T, #T)

#define TypeName _Generic(*(T), \
        GEN_VAR_TYPE_NAME(Size),
        GEN_VAR_TYPE_NAME(Point))

...
// test
const Point *ppt = &pt;
printf("I'm a %s\n", TypeName(ppt));
// print I'm a Point

---
@beto
« Last Edit: April 18, 2014, 07:45:29 PM by aMarCruz »

Offline Pelle

  • Administrator
  • Member
  • *****
  • Posts: 2266
    • http://www.smorgasbordet.com
Re: _Generic is not standard compliant with C11 (Pelles C 7 and v8 RC2)
« Reply #2 on: April 20, 2014, 11:48:40 AM »
Well, the _Generic feature isn't super well defined in the standard IMO. I have seen several lengthy debates about it in various forums, but little conclusion.
I'm aware that _Generic *may* need more work, but I need more/better information before doing anything...
/Pelle

aMarCruz

  • Guest
Re: _Generic is not standard compliant with C11 (Pelles C 7 and v8 RC2)
« Reply #3 on: April 21, 2014, 09:38:18 AM »
Thanks Pelle.

Yes, the standard is not clear there. It is a matter of semantics, pass pointer to a function has the same effect as passing a const pointer because pointers are passed by value.
I understood until I ran these tests...

Code: [Select]
#include <stdio.h>

typedef struct { int A; } TYPE;

int func_P(TYPE *p) {
puts("TYPE*");
p->A++;
return p->A;
}
int func_CT(const TYPE *p) {
puts("const TYPE*");
//p->A++; //can't do that
return p->A + 1;
}
//this is redundant
int func_CP(TYPE *const p) {
puts("TYPE *const");
p->A++;
return p->A;
}
#define func(_1) _Generic(_1, \
TYPE*      : func_P,      \
const TYPE*: func_CT)(_1)

int main(void)
{
TYPE  a, b;
int   i;
const TYPE       *CT  = &a;  // can't change *CT (CT->A)
TYPE *const       CP  = &a;  // can't change CP
const TYPE *const CPT = &a;  // can't change CPT nor *CPT

// test
CT = &b;        //ok, can change CT pointer
CT = &a;
//CT->A = 1;    //error ok, *CT data is const
a.A = 1;
i = func(CT);
printf("func(const TYPE *CT) returns %d , CT->A is %d (expected 1)\n", i, CT->A);

//CP = &b;      //error ok, CP pointer is const
CP->A = 1;      //ok, can change *CP data
a.A = 1;
i = func(CP);
printf("func(TYPE *const CP) returns %d , CT->A is %d (expected 2)\n", i, CP->A);

//CPT++; //error ok, CPT is const
//CPT->A++; //error ok, *CPT is const
a.A = 1;
i = func(CPT);
printf("func(const TYPE *const CPT) returns %d , CT->A is %d (expected 1)\n", i, CPT->A);

return 0;
}

The output is:

const TYPE*                                                   
func(const TYPE *CT) returns 2 , CT->A is 1 (expected 1)       
TYPE*                                                         
func(TYPE *const CP) returns 2 , CT->A is 2 (expected 2)       
const TYPE*                                                   
func(const TYPE *const CPT) returns 2 , CT->A is 1 (expected 1)


Thanks again.

PS: anyway, in _Generic, some compilers know the difference between *p and *const p, so writing portable code is complicated :(

--
@beto

« Last Edit: April 21, 2014, 09:44:48 AM by aMarCruz »

Offline Pelle

  • Administrator
  • Member
  • *****
  • Posts: 2266
    • http://www.smorgasbordet.com
Re: _Generic is not standard compliant with C11 (Pelles C 7 and v8 RC2)
« Reply #4 on: April 21, 2014, 05:21:14 PM »
I deliberately use the unqualified type for _Generic, which seems correct, but even this can be debated I guess.
I think the main/only reason _Generic was added was to make tgmath.h work without "compiler magic". A quick fix, in a way.
/Pelle

aMarCruz

  • Guest
Re: _Generic is not standard compliant with C11 (Pelles C 7 and v8 RC2)
« Reply #5 on: April 22, 2014, 02:45:24 AM »
Yeeh, you right.

Later, I will post a partial implementation of P99 (a preprocessor library) adapted to work with Pelles C and Clang Windows.
Thanks again.

@beto