c-如何将C11关键字_Generic与struct一起使用



相关

  • 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_tprint_v2i是函数指示符,它们将以(&(obj))部分作为参数进行调用。因此,如果我们将一个int32_t传递给_Generic,那么它将选择函数print_int32_t并将其调用为print_int32_t(&sA)

输出:

[sA] @ line [32]: [555]
[vA] @ line [33]: [111][999]

最新更新