编译时的 C 函数装饰器(包装器)

发布于 2024-07-29 04:58:06 字数 651 浏览 3 评论 0原文

我试图在预处理器的帮助下改变C中某些函数的行为; 并添加可以设置为开或关的可选参数...

可选参数的基本模式很简单:

#ifdef OPT_PARAM
  #define my_func(a, b, opt) _my_func(a, b, opt)
#else
  #define my_func(a, b, opt) _my_func(a, b)
#endif

/*the rest of the code always calls "my_func" with all the params
and not the underscored version...*/

#ifdef OPT_PARAM
void _my_func(int a, int b, int opt)
#else
void _my_func(int a, int b)
#endif
{
  /*... more #ifdefs surrounding opt uses */
}

有条件地包装函数的模式类似,但问题是下划线开始累加(一个额外的下划线)每个级别的嵌套,可以是不同的函数,也可以只是下一个级别的#define(以防未包装)。

那么,关于如何降低代码复杂性有什么想法吗?

PS 我愿意使用 Python...但这是针对驱动程序的:-(

I'm trying to change the behaviour of some functions in C with help of the preprocessor; and also add optional parameters that can be set on or off...

The basic pattern for the optional parameters is easy:

#ifdef OPT_PARAM
  #define my_func(a, b, opt) _my_func(a, b, opt)
#else
  #define my_func(a, b, opt) _my_func(a, b)
#endif

/*the rest of the code always calls "my_func" with all the params
and not the underscored version...*/

#ifdef OPT_PARAM
void _my_func(int a, int b, int opt)
#else
void _my_func(int a, int b)
#endif
{
  /*... more #ifdefs surrounding opt uses */
}

the pattern for wrapping a function conditionally is similar, but the problem is that the underscores start to add up (one extra for each level of nesting, that can be a different function or just a #define for the next level in case it's not wrapped).

So, any ideas about how to reduce the code complexity here?

P.S. I'd be willing to use Python... but this is for a driver :-(

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

终难愈 2024-08-05 04:58:06

似乎您想使用默认参数或 C 中不可用的东西。这似乎是一个坏主意。 为什么不以更 C 的方式处理事情,如果您不想指定参数,则只需传递 NULL 或 -1(标准)。

void function (int a, int b, int c) {
  if (c != -1) {
    // something
  }
}

function(a,b,-1);
function(a,b,c);

Seems like you want to use default arguments or something that is not available in C. This seems to be a bad idea. Why not handle things in a more C fashion, where if you don't want to specify an argument you just pass NULL or -1 (standard).

void function (int a, int b, int c) {
  if (c != -1) {
    // something
  }
}

function(a,b,-1);
function(a,b,c);
心奴独伤 2024-08-05 04:58:06

可以使用C++编译器吗? 您可以使用(C++ 功能)只是函数重载。

另一种选择是

#ifdef OPT_PARAM
#  define OPT(X) , X
#else
#  define OPT(X)  
#endif

int my_func(int a, int b OPT(int opt) ) {
#ifndef OPT_PARAM
  int opt = default_value;
#endif
  ... // Rest of code
}  


...
// calling it
my_func(2, 4 OPT( 42 ) );

Can you use a C++ compiler? You could use (of C++ features) just function overloading.

Another option is

#ifdef OPT_PARAM
#  define OPT(X) , X
#else
#  define OPT(X)  
#endif

int my_func(int a, int b OPT(int opt) ) {
#ifndef OPT_PARAM
  int opt = default_value;
#endif
  ... // Rest of code
}  


...
// calling it
my_func(2, 4 OPT( 42 ) );
做个少女永远怀春 2024-08-05 04:58:06

我认为这可能更接近你想要的,但我不确定。 我的理解是,这个想法是允许 c 函数具有任意数量的参数,这些参数经过类型检查并且可以在编译时消除。

让我通过引用标准来警告您在标识符中使用下划线。 您可能会遇到保留的标识符。 然而,我不知道这种情况的可能性。

ISO/IEC 9899:1999 (E) 7.1.3

——所有以a开头的标识符
下划线和大写字母
字母或另一个下划线是
始终保留供任何使用。

该解决方案需要 GCC。 GCC 的版本还必须支持弱符号。 这个想法是允许编译器使用弱符号查找正确的函数定义。 此外,通过使用编译器应修剪死分支的知识来简化函数的内容,即:

if (0) { ... }

在编译时无需进一步分析(GCC 4.x 当然会这样做)。 通过将不存在的可选参数定义为 c 预处理器 (cpp) 符号,您可以避免在函数体中出现 cpp 条件(如果需要)。 请参阅下面如何为 f_opt0 定义 opt1 和 opt2。

#include <assert.h>
#include <stdio.h>

extern void f_opt0(int a, int b) __attribute__((weak));
extern void f_opt1(int a, int b, int opt1) __attribute__((weak));
extern void f_opt2(int a, int b, int opt1, int opt2) __attribute__((weak));

#ifdef OPT0
void f_opt0(int a, int b) {
#define opt1 0
#define opt2 0
#endif
#ifdef OPT1
void f_opt1(int a, int b, int opt1) {
#define opt2 0
#endif
#ifdef OPT2
void f_opt2(int a, int b, int opt1, int opt2) {
#endif
  if (opt1) printf("opt1=%d\n", opt1);
  if (opt2) printf("opt2=%d\n", opt2);
  printf("a+b=%d\n", a+b);
  #undef opt1
  #undef opt2
}

#define f(a, b, o1, o2) \
  if (f_opt2) f_opt2(a, b, o1, o2); \
  else if (f_opt1) f_opt1(a, b, o1); \
  else if (f_opt0) f_opt0(a, b); \
  else { assert(0 && "no f() defined!"); }

int main(void) {
  f(1, 2, 1, 1);
  return 0;
}

我的测试非常有限,而且我并不提倡用 C 语言来实现这种良好的设计。它似乎很容易出现问题,而且很难理解。 但是,我希望它能实现您的目标。

I think this may be closer to what you want, but I am unsure. My understanding is the idea is to allow c functions with arbitrary numbers of arguments, that are type checked and can be eliminated at compile time.

Let me warn you about the use of underscores in identifiers, by quoting the standard. You may run into a reserved identifier. However, the likelihood of this is unknown to me.

ISO/IEC 9899:1999 (E) 7.1.3

— All identifiers that begin with an
underscore and either an uppercase
letter or another underscore are
always reserved for any use.

This solution requires GCC. The version of GCC must also support weak symbols. The idea is to allow the compiler to look for the right function definition using weak symbols. Additionally the contents of the function are simplified by using the knowledge that the compiler should prune dead branches, ie:

if (0) { ... }

at compile time without further analysis (GCC 4.x certainly does this). By defining the non-existent optional parameters as c pre-processor (cpp) symbolsyou can avoid having cpp conditionals in the function body (if so desired). See how opt1 and opt2 are defined for f_opt0 below.

#include <assert.h>
#include <stdio.h>

extern void f_opt0(int a, int b) __attribute__((weak));
extern void f_opt1(int a, int b, int opt1) __attribute__((weak));
extern void f_opt2(int a, int b, int opt1, int opt2) __attribute__((weak));

#ifdef OPT0
void f_opt0(int a, int b) {
#define opt1 0
#define opt2 0
#endif
#ifdef OPT1
void f_opt1(int a, int b, int opt1) {
#define opt2 0
#endif
#ifdef OPT2
void f_opt2(int a, int b, int opt1, int opt2) {
#endif
  if (opt1) printf("opt1=%d\n", opt1);
  if (opt2) printf("opt2=%d\n", opt2);
  printf("a+b=%d\n", a+b);
  #undef opt1
  #undef opt2
}

#define f(a, b, o1, o2) \
  if (f_opt2) f_opt2(a, b, o1, o2); \
  else if (f_opt1) f_opt1(a, b, o1); \
  else if (f_opt0) f_opt0(a, b); \
  else { assert(0 && "no f() defined!"); }

int main(void) {
  f(1, 2, 1, 1);
  return 0;
}

My testing was very limited, and I do not advocate this as good design in C. It seems prone to problems and is troublesome to comprehend. However, I hope it addresses your goals.

谜兔 2024-08-05 04:58:06

最后,我只是添加了一个新的装饰器,它统一处理额外的参数,并通过更具描述性的名称更改了晦涩的下划线。

现在它是一个更加正交的设计,我可以在编译时插入和拔出行为,而无需运行时开销。

In the end I just added a new decorator that handled uniformly the extra parameters and changed the obscure underscores by more descriptive names.

Now it's a more orthogonal design in which I can plug and unplug behaviour at compile time with no runtime overhead.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文