История изменений
Исправление LINUX-ORG-RU, (текущая версия) :
Либо делаешь два генерик принта, один для базовых типов, второй для составных имеющих одинаковое количество полей.
Либо пишешь как тут ниже «проксирующие» функции. В printf
не сувай =) просто структуру по значению, надо совать поля структуры, раскрывать структуру и форматировать вывод значений полей составного типа.
Так что либо вот так, всё в одном
#include <stdio.h>
#include <stdlib.h>
struct DPOINT2
{
double X,Y;
} DPOINT2;
struct FPOINT2
{
float X,Y;
} FPOINT2;
#define MSG1 "Значение"
#define MSG2 "вне заданного диапазона\n"
void p_int(int x)
{
printf( MSG1 " i %d " MSG2, x);
}
void p_long(long x)
{
printf( MSG1 " l %ld " MSG2, x);
}
void p_double(double x)
{
printf( MSG1 " d %f " MSG2, x);
}
void p_float(float x)
{
printf( MSG1 " f %f " MSG2, x);
}
void p_fpoint(struct FPOINT2 x)
{
printf( MSG1 " d(%6.3f, %6.3f) " MSG2 ,x.X,x.Y);
}
void p_dpoint(struct DPOINT2 x)
{
printf( MSG1 " f(%6.3f, %6.3f) " MSG2 ,x.X,x.Y);
}
#define PRINT(x) \
_Generic( (x), \
int : p_int, \
long : p_long, \
double : p_double, \
float : p_float, \
struct DPOINT2 : p_dpoint, \
struct FPOINT2 : p_fpoint )(x)
int main(int argc, char *argv[])
{
struct DPOINT2 dp = {.X=42.0, .Y=0.42};
struct FPOINT2 fp = {.X=42.0, .Y=0.42};
PRINT(dp);
PRINT(((struct DPOINT2){42.0,0.42}));
PRINT(fp);
PRINT(((struct FPOINT2){42.0,0.42}));
PRINT(1);
PRINT(1L);
PRINT(1.0f);
PRINT(1.0);
return 0;
}
Либо вот так, раздельно
#include <stdio.h>
#include <stdlib.h>
struct DPOINT2
{
double X,Y;
} DPOINT2;
struct FPOINT2
{
float X,Y;
} FPOINT2;
#define MSG1 "Значение"
#define MSG2 "вне заданного диапазона\n"
#define PRINT2(x) \
_Generic( (x), \
struct DPOINT2 : printf( MSG1 " d(%6.3f, %6.3f) " MSG2 ,x.X,x.Y),\
struct FPOINT2 : printf( MSG1 " f(%6.3f, %6.3f) " MSG2 ,x.X,x.Y) )
#define PRINT1(x) \
_Generic( (x), \
int : printf( MSG1 " i %d " MSG2, x),\
long : printf( MSG1 " l %ld " MSG2, x),\
double : printf( MSG1 " d %f " MSG2, x),\
float : printf( MSG1 " f %f " MSG2, x) )
int main(int argc, char *argv[])
{
struct DPOINT2 dp = {.X=42.0, .Y=0.42};
struct FPOINT2 fp = {.X=42.0, .Y=0.42};
PRINT2(dp);
PRINT2(((struct DPOINT2){42.0,0.42}));
PRINT2(fp);
PRINT2(((struct FPOINT2){42.0,0.42}));
PRINT1(1);
PRINT1(1L);
PRINT1(1.0f);
PRINT1(1.0);
return 0;
}
Ты хочешь просто вот так
#define PRINT1(x) \
_Generic( (x), \
int : printf( MSG1 " i %d " MSG2, x),\
long : printf( MSG1 " l %ld " MSG2, x),\
double : printf( MSG1 " d %f " MSG2, x),\
float : printf( MSG1 " f %f " MSG2, x),\
struct DPOINT2 : printf( MSG1 " d(%6.3f, %6.3f) " MSG2 ,x.X,x.Y),\
struct FPOINT2 : printf( MSG1 " f(%6.3f, %6.3f) " MSG2 ,x.X,x.Y) )
Вроде логично смотрится и красиво, только вот работать не будет для базовых типов int
и так далее, все попрытки это обойти приведут к починил тут, сломал там и так и будут качели, все поля в одни скобочки, псевдополя для базовых типов, вместо полей передача по значению самой структуры и так далее, но не надо. Это как приводить 42.0
из float
к массиву char[4]
а потом к uint32_t
и ожидать увидеть 42
в значении инта =))) Си это пускает спокойно так как предполагается что ты делаешь с данными то что тебе нужно, и если тебе нужно получить херню непонятную, будет исполнено и ты её получишь =)
Я сам постоянно косячу в этом плане :(
Если я тут где-то ошибаюсь буду рад если поправите :).
Исходная версия LINUX-ORG-RU, :
Либо делаешь два генерик принта, один для базовых типов, второй для составных имеющих одинаковое количество полей.
Либо пишешь как тут ниже «проксирующие» функции. В printf
не сувай =) просто структуру по значению, надо совать поля структуры, раскрывать структуру и форматировать вывод значений полей составного типа.
Так что либо вот так, всё в одном
#include <stdio.h>
#include <stdlib.h>
struct DPOINT2
{
double X,Y;
} DPOINT2;
struct FPOINT2
{
float X,Y;
} FPOINT2;
#define MSG1 "Значение"
#define MSG2 "вне заданного диапазона\n"
void p_int(int x)
{
printf( MSG1 " i %d " MSG2, x);
}
void p_long(long x)
{
printf( MSG1 " l %ld " MSG2, x);
}
void p_double(double x)
{
printf( MSG1 " d %f " MSG2, x);
}
void p_float(float x)
{
printf( MSG1 " f %f " MSG2, x);
}
void p_fpoint(struct FPOINT2 x)
{
printf( MSG1 " d(%6.3f, %6.3f) " MSG2 ,x.X,x.Y);
}
void p_dpoint(struct DPOINT2 x)
{
printf( MSG1 " f(%6.3f, %6.3f) " MSG2 ,x.X,x.Y);
}
#define PRINT(x) \
_Generic( (x), \
int : p_int, \
long : p_long, \
double : p_double, \
float : p_float, \
struct DPOINT2 : p_dpoint, \
struct FPOINT2 : p_fpoint )(x)
int main(int argc, char *argv[])
{
struct DPOINT2 dp = {.X=42.0, .Y=0.42};
struct FPOINT2 fp = {.X=42.0, .Y=0.42};
PRINT(dp);
PRINT(((struct DPOINT2){42.0,0.42}));
PRINT(fp);
PRINT(((struct FPOINT2){42.0,0.42}));
PRINT(1);
PRINT(1L);
PRINT(1.0f);
PRINT(1.0);
return 0;
}
Либо вот так, раздельно
#include <stdio.h>
#include <stdlib.h>
struct DPOINT2
{
double X,Y;
} DPOINT2;
struct FPOINT2
{
float X,Y;
} FPOINT2;
#define MSG1 "Значение"
#define MSG2 "вне заданного диапазона\n"
#define PRINT2(x) \
_Generic( (x), \
struct DPOINT2 : printf( MSG1 " d(%6.3f, %6.3f) " MSG2 ,x.X,x.Y),\
struct FPOINT2 : printf( MSG1 " f(%6.3f, %6.3f) " MSG2 ,x.X,x.Y) )
#define PRINT1(x) \
_Generic( (x), \
int : printf( MSG1 " i %d " MSG2, x),\
long : printf( MSG1 " l %ld " MSG2, x),\
double : printf( MSG1 " d %f " MSG2, x),\
float : printf( MSG1 " f %f " MSG2, x) )
int main(int argc, char *argv[])
{
struct DPOINT2 dp = {.X=42.0, .Y=0.42};
struct FPOINT2 fp = {.X=42.0, .Y=0.42};
PRINT2(dp);
PRINT2(((struct DPOINT2){42.0,0.42}));
PRINT2(fp);
PRINT2(((struct FPOINT2){42.0,0.42}));
PRINT1(1);
PRINT1(1L);
PRINT1(1.0f);
PRINT1(1.0);
return 0;
}
Ты хочешь просто вот так
#define PRINT1(x) \
_Generic( (x), \
int : printf( MSG1 " i %d " MSG2, x),\
long : printf( MSG1 " l %ld " MSG2, x),\
double : printf( MSG1 " d %f " MSG2, x),\
float : printf( MSG1 " f %f " MSG2, x),\
struct DPOINT2 : printf( MSG1 " d(%6.3f, %6.3f) " MSG2 ,x.X,x.Y),\
struct FPOINT2 : printf( MSG1 " f(%6.3f, %6.3f) " MSG2 ,x.X,x.Y) )
Вроде логично смотрится и красиво, только вот работать не будет для базовых типов int
и так далее, все попрытки это обойти приведут к починил тут, сломал там и так и будут качели, все поля в одни скобочки, псевдополя для базовых типов, вместо полей передача по значению самой структуры и так далее, но не надо. Это как приводить 42.0
из float
к массиву char[4]
а потом к uint32_t
и ожидать увидеть 42
в значении инта =))) Си это пускает спокойно так как предполагается что ты делаешь с данными то что тебе нужно, и если тебе нужно получить херню непонятную, будет исполнено и ты её получишь =)
Я сам постоянно косячу в этом плане :(