是否可以将结构成员名称作为函数中的参数传递?

Is it possible to pass a struct member name as an argument in a function?

提问人:Briac Bruneau Sunkkie 提问时间:11/12/2023 最后编辑:Briac Bruneau Sunkkie 更新时间:11/12/2023 访问量:71

问:

我正在编写启发式方法来解决网格问题,但我最终在函数体中重复了 4 次相同的代码块,每次差异都非常小,因此建议我编写一个内联函数以使其看起来更好。

我的网格是一个具有成员大小的结构体,线条由另一个结构体表示:

typedef struct
{
  int size;
  binline *lines;
} grid_t;

typedef struct
{
  uint64_t ones;
  uint64_t zeros;
} gridline;

1(resp zeros)是一个二进制整数,其中位表示 1(resp zeros)在网格中的位置,我选择以这种方式表示线,因为它们可以是 1 或 0 或空。

所以我现在有一个函数,条目看起来像,在正文中我测试“c”是 ONE 还是 ZERO,然后应用相应的启发式方法。static inline bool subheuristic(grid_t *grid, ..., ..., char c)

问题是它并没有真正减少代码大小...... 我想知道是否可以将“一些”作为参数,然后在正文中立即使用它来访问,例如,在这种情况下,这将真正减小代码大小。grid->gridline.some

C 性能 优化 参数 内联

评论

2赞 Some programmer dude 11/12/2023
C 没有做这样的事情所需的反射
0赞 Jim Rogers 11/12/2023
您似乎已经制作了比需要的更复杂的数据结构。据我了解您的描述,grid_t 的 lines 成员包含 1 和 0,而 gridline 的 ones 成员包含 1 的索引值,zeros 成员包含零的索引值。看来grid_t线和网格线只是相同信息的两种表示形式。
0赞 tstanisl 11/12/2023
如果可能的话,您能否提供更多简化的源代码?即使使用某些形式的反射,也可以用 C 编写通用代码。

答:

0赞 tstanisl 11/12/2023 #1

有一些方法可以在 C 中实现所需的功能。

不能将成员的名称传递给函数,可以在结构中传递成员的偏移量。偏移量可以从 中定义的标准宏获得。offsetofstddef.h

#include <stddef.h>

uint64_t get_grid_bits(const gridline *gl, size_t offset) {
  return *(uint64_t*)( (char*)gl + offset );
}

...

gridline gl = { .ones = 13, .zeros = 42 };
get_grid_bits(&gl, offsetof(gridline, ones)); // return 13
get_grid_bits(&gl, offsetof(gridline, zeros)); // return 42

请注意,该行为完全由 C 标准定义,因为任何对象的任何部分都可以通过类型的指针算术来访问。char*

魅力一样工作。

评论

0赞 Briac Bruneau Sunkkie 11/12/2023
删除 const 关键字,是否可以修改函数中 1/0s 字段的值?假设 I 偏移量和网格指针作为参数
0赞 tstanisl 11/12/2023
@BriacBruneauSunkkie,是的,假设原始对象是在没有限定符的情况下声明的。 很好,但是会调用未定义的行为。constgridline gl = { ... }const gridline gl = { ... }
0赞 0___________ 11/12/2023
仅当使用 offsetof 时,才像超级按钮一样工作。但这并不妨碍通过任何其他论点。然后它将调用 UB。要使其 100% 无 UB,您需要添加 asserst 或运行时检查
0赞 tstanisl 11/12/2023
@0___________.可以使用宏#define get_grid_bits(gl,member) get_grid_bits(gl, offsetof(gridline, member))
0赞 0___________ 11/12/2023
?godbolt.org/z/njKq4Kb8r
0赞 0___________ 11/12/2023 #2

这在 C 语言中是不可能的,但我会使用一个内联函数,当您将常量表达式作为 和 传递时,该函数将很好地优化为非常简单的操作bittype

typedef struct
{
  uint64_t data[2];
} gridline;

typedef enum {zeroes, ones} type; 

static inline __attribute__((always_inline)) uint64_t get_grid_bits(const gridline * restrict gl, const type t) 
{
  return gl -> data[t];
}

static inline __attribute__((always_inline)) void set_grid_bit(gridline * restrict gl, const type t, int bit) 
{
    gl -> data[t] |= 1ULL << bit;
}

static inline __attribute__((always_inline)) void reset_grid_bit(gridline * restrict gl, const type t, int bit) 
{
    gl -> data[t] &= ~(1ULL << bit);
}

static inline __attribute__((always_inline)) int get_grid_bit(const gridline * restrict gl, const type t, int bit) 
{
    return !!(gl -> data[t] & (1ULL << bit));
}

https://godbolt.org/z/dzMM7vfnb