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

问题描述 投票:0回答:1

相关

大家好!

我正在编写一个区分输入结构类型的宏。 我在 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)?

谢谢!

c generics keyword c11 winlibs
1个回答
2
投票

这样做的原因是所有

_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)

	
© www.soinside.com 2019 - 2024. All rights reserved.