Try this please.
This code don't compile (fail with error 2502: Multiple associations for type ... etc)
// 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:
#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
(Sorry, I was wrong. I have Clang in mingw mode, mingw 4.8.1 is not working with _Generic).
An workaround is something like...
#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
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...
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...
#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
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.
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