【问题标题】:How can multiple variables be passed to a function cleanly in C?如何在 C 中将多个变量干净地传递给函数?
【发布时间】:2010-04-12 21:09:00
【问题描述】:

我正在开发一个具有不同输出功能(数字输出、串行、模拟等)的嵌入式系统。我正在尝试找出一种干净的方法来传递许多将控制这些函数的变量。

我不需要太频繁地传递它们,但我希望有一个函数可以读取输入数据(在这种情况下来自 TCP 网络),然后解析数据(IE,第 3 byte 包含 8 个数字输出的状态(根据该字节中的哪个位是高或低)),并将其放入一个变量中,然后我可以在程序的其他地方使用。

我希望该函数与 main() 函数分开,但这样做需要将指针传递给它要写入的大约 20 个变量。我知道我可以使变量成为全局变量,但我试图通过将函数传递给函数来使函数被允许编辑该变量时变得明显,从而使调试变得更容易。

我最好的想法是一个结构,只需传递一个指向它的指针,但不确定是否有更有效的方法,特别是因为实际上只有一个函数需要一次访问所有它们,而大多数其他人只需要将存储在这组状态变量中的部分信息。

那么无论如何,有没有一种简洁的方法可以一次在函数之间发送许多需要编辑的变量?

【问题讨论】:

  • 你知道struct,对吧?

标签: c function argument-passing


【解决方案1】:

使用带有指向它的指针的结构确实是一个不错的选择。代码可能写得有点长,但看起来不错。您可以按值传递结构,但按引用传递将避免复制数据。

另一种选择是创建一个由结构组成的结构。然后,您可以通过传递整个数据、仅传递其中的一两个或结构的单个元素来更有选择性地传递给每个函数的数据。

typedef struct a {
  struct b {
    int b1;
    int b2;
  } b_s;
  struct c {
    int c1;
    int c2;
  } c_s;
} a_s;

【讨论】:

    【解决方案2】:

    这是“参数块”的经典用法——只是一个指向知名结构的指针。

    优点包括: 高效,因为对给定参数的任何访问都是地址加偏移量;易于调试(您可以在一个“打印”中查看所有参数);局部性(很好地缓存);很容易变成一组可堆叠的调用,您不会轻易知道堆栈中的任何给定函数可能需要哪些参数。

    缺点包括:你无法通过查看函数调用来判断哪些参数对被调用者很重要——你必须知道,或者去挖掘该函数的源代码;更容易引起副作用,尤其是您允许被调用的函数修改块(坏,坏,坏!);增加耦合度(每个函数都可以看到每个参数,这可能会导致诱惑......)

    【讨论】:

      【解决方案3】:

      我要做的就是把它们都写下来接受结构。在程序运行后如果效率是一个问题,应该很容易返回并更改那些只使用一个或两个变量的函数,只接受这些变量作为参数。

      【讨论】:

        【解决方案4】:

        将指针传递给结构通常是“干净”的方式。智能地定义数据结构可以赋予此方法强大的功能和灵活性。以数据结构为例:

        struct func_params {
            int type;
            union {
                struct {
                    int    port;
                    int    direction;
                    long   target_addr;
                } digital_io;
                struct {
                    int    channel;
                    long   sample_rate;
                } analog_in;
                struct {
                    int    channel;
                    int    async;
                    int    hold_output;
                } analog_out;
                struct {
                    int    port;
                    int    direction;
                    int    encoding;
                } serial_io;
            };
        };
        

        用类似的东西定义你的函数

        my_function (struct func_params* pStruct, size_t length)
        

        使用该函数时,首先创建一个足够大的缓冲区,以包含数据结构以及您将要发送到该函数的任何潜在可变长度数据的大小(例如,发送端口的数据)。数据缓冲区的第一部分将包含您定义的结构。缓冲区的其余部分(length - sizeof(struct func_params) 字节)将是您存储数据的位置。您的函数读取type 结构成员并确定如何解释结构的其余部分,在处理完结构后,它可以确定如何解释可变长度数据部分。

        这可能比您想象的要复杂一些。在嵌入式世界中,许多通信协议(例如 SCSI)通过发送标头进行通信,后跟这样的可变长度数据部分。它为函数提供了一个干净的界面,很好地将相关信息捆绑在一起,并且在不更改调用参数的情况下更容易更改函数。

        【讨论】:

          【解决方案5】:

          我会说结构是你最好的选择。如果您不需要特定函数中的所有变量,则可以选择仅将其中一个成员传递给函数。如果您需要设置单独的位,您也可以从第 3 个字节的位域中受益。当然,这个位域也可以是你的结构体的成员。

          【讨论】:

            猜你喜欢
            • 2021-10-23
            • 2021-12-31
            • 1970-01-01
            • 1970-01-01
            • 2012-08-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-06-18
            相关资源
            最近更新 更多