相关
大家好!
我正在编写一个区分输入结构类型的宏。 我在 Windows 下使用 WinLibs 的 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.
所以,我的问题是:如何制作以单个值和结构作为输入的宏(例如C)?
谢谢!
这样做的原因是所有
_Generic
的情况都会随着宏而扩展。为了避免这种情况,需要将特定于类型的部分移到 _Generic
表达式之外。如果我们用对自定义函数的调用替换您的 printf
调用,然后将参数放置在 _Generic
之外的这些函数中,我们就可以实现这一目标。
并且为了不必按值传递结构等,也许可以让这些自定义函数接受指针。
与问题没有直接关系的其他代码审查:
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)