相关
- C11中_Generic的语法和示例用法
- _泛型适用于typedef结构还是仅适用于基元类型
- 如何将_Generic与C中类型定义的结构一起使用
大家好!
我正在编写一个宏来区分输入结构的类型。我在WinLibs的Windows下使用MinGW GCC:https://winlibs.com/
这里的一个例子:C11中_Generic的语法和示例用法工作得很好,我能够写同样的宏(例A(
// Example A (Single Value):
#include <stdio.h>
#include <stdint.h>
//
typedef int32_t i32;
typedef uint32_t u32;
typedef int64_t i64;
typedef uint64_t u64;
// any single value
#define deb_single(val)
printf("[%s]: ", #val);
_Generic( (val),
default : puts("UNKNOWN_TYPE"),
i32 : printf("[%d]" , (i32)val),
u32 : printf("[%u]" , (u32)val),
i64 : printf("[%lld]" , (i64)val),
u64 : printf("[%llu]" , (u64)val)
);
printf("Func [%s], line [%d]n", __func__, __LINE__);
i32 main()
{
i32 A = 111;
u32 B = 222;
i64 C = 333;
u64 D = 444;
deb_single(A);
deb_single(B);
deb_single(C);
deb_single(D);
return 0;
}
// Result_of Example A:
[A]: [111]Func [main], line [35]
[B]: [222]Func [main], line [36]
[C]: [333]Func [main], line [37]
[D]: [444]Func [main], line [38]
// Endof Example A.
现在,几乎相同的方法(使用typeof(适用于两个相同类型值的结构(示例B(
// Example B (Struct of two same-type values):
#include <stdio.h>
#include <stdint.h>
//
typedef int32_t i32;
typedef uint32_t u32;
typedef float r32;
typedef double r64; // only for printf cast
typedef struct _tag_v2i { i32 x; i32 y; } v2i;
typedef struct _tag_v2u { u32 x; u32 y; } v2u;
typedef struct _tag_v2f { r32 x; r32 y; } v2f;
//
#define deb_struct(str)
printf("[%s] @ line [%d]: ", #str, __LINE__);
_Generic( (typeof(str)){0},
default : puts("UNKNOWN_TYPE"),
struct _tag_v2i : printf("[%d][%d]n", (i32)str.x, (i32)str.y),
struct _tag_v2u : printf("[%u][%u]n", (u32)str.x, (u32)str.y),
struct _tag_v2f : printf("[%.2f][%.2f]n", (r64)str.x, (r64)str.y)
);
i32 main()
{
v2i vA = {111,999};
v2u vB = {222,888};
v2f vC = {1.5f, 5.25f};
deb_struct(vA);
deb_struct(vB);
deb_struct(vC);
return 0;
}
// Result_of Example B:
[vA] @ line [30]: [111][999]
[vB] @ line [31]: [222][888]
[vC] @ line [32]: [1.50][5.25]
// Endof Example B.
然而,我很难将单个值和结构混合在一起(示例C(
// Example C [/*ERRORS*/]:
#include <stdio.h>
#include <stdint.h>
//
typedef int32_t i32;
typedef struct _tag_v2i { i32 x; i32 y; } v2i;
//
#define deb_struct(str)
printf("[%s] @ line [%d]: ", #str, __LINE__);
_Generic( (typeof(str)){0},
default : puts("UNKNOWN_TYPE"),
i32 : printf("[%d]" , (i32)str),
struct _tag_v2i : printf("[%d][%d]n", (i32)str.x, (i32)str.y)
);
i32 main()
{
i32 sA = 555;
v2i vA = {111,999};
deb_struct(sA);
deb_struct(vA);
return 0;
}
// Result_of Example C:
error: request for member 'x' in something not a structure or union
14 | struct _tag_v2i : printf("[%d][%d]n", (i32)str.x, (i32)str.y),
error: request for member 'y' in something not a structure or union
14 | struct _tag_v2i : printf("[%d][%d]n", (i32)str.x, (i32)str.y),
error: aggregate value used where an integer was expected
23 | deb_struct(vA);
// Endof Example C.
所以,我的问题是:如何制作以单个值AND struct(Ex.C(作为输入的宏
谢谢!
原因是_Generic
的所有情况都将用宏展开。为了避免这种情况,需要将特定于类型的部分移动到_Generic
表达式之外。如果我们将printf
调用替换为对自定义函数的调用,然后将参数放置在_Generic
之外的那些函数中,我们就可以实现这一点。
为了不必按值传递structs等,可以让这些自定义函数接受指针。
与问题没有直接关系的杂项代码审查:
- 使用
stdint.h
中的类型,而不是发明自己的非标准类型 - 使用
inttypes.h
打印它们,然后在printf中就不需要强制转换了 - 无需(目前(非标准
typeof
- 不要在宏中写分号
- 当某个东西不是字符串时,不要将其命名为
str
清理代码:
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
typedef struct
{
int32_t x;
int32_t y;
} v2i;
static void print_int32_t (const int32_t* obj)
{
printf("[%"PRIi32"]n", *obj);
}
static void print_v2i (const v2i* obj)
{
printf("[%"PRIi32"][%"PRIi32"]n", obj->x, obj->y);
}
#define deb_struct(obj)
printf("[%s] @ line [%d]: ", #obj, __LINE__);
_Generic((obj),
int32_t: print_int32_t,
v2i: print_v2i
) (&(obj))
int main (void)
{
int32_t sA = 555;
v2i vA = {111,999};
deb_struct(sA);
deb_struct(vA);
}
现在print_int32_t
和print_v2i
是函数指示符,它们将以(&(obj))
部分作为参数进行调用。因此,如果我们将一个int32_t
传递给_Generic
,那么它将选择函数print_int32_t
并将其调用为print_int32_t(&sA)
。
输出:
[sA] @ line [32]: [555]
[vA] @ line [33]: [111][999]