【问题标题】:Multiple Parameters in a single Parameter (functions) in C/C++C/C++ 中单个参数(函数)中的多个参数
【发布时间】:2012-01-31 18:04:42
【问题描述】:

好吧,这可能听起来有点含糊不清,但那是因为我不知道如何用不同的词来表达。我将尝试解释我的意思:在某些库中,'init' 函数通常接受一些参数,但该参数随后接受多个参数(对..)。一个例子,应该是这样的:

apiHeader.h

#define API_FULLSCREEN   0x10003003
#define API_NO_DELAY     0x10003004
#define API_BLAH_BLAH    0x10003005

main.c:

apiInit(0, 10, 10, 2, API_FULLSCREEN | API_NO_DELAY | API_BLAH_BLAH);

这是如何工作的?我在任何地方都找不到答案,很可能是因为我不知道它的实际名称,所以我不知道要搜索什么。这在我当前的项目中会非常有用。

提前致谢!

【问题讨论】:

  • 正如你所写,它不会工作,因为你的标志没有设置不同的位。
  • 这是我意识到的,它主要用于示例目的。原谅我,我已经30个小时没睡了! :(

标签: c++ c function parameters bit-manipulation


【解决方案1】:

该参数通常称为“$FOO flags”,其值为or-ed。关键是参数是一个数字类型,构造为多个可能值的按位or

在处理函数中,通常使用按位测试值and

if ( (flags & API_FULLSCREEN) != 0 )

您必须小心以保持 OR 运算线性的方式分配值。换句话说,不要像在标题中那样在两个不同的or-able 值中设置相同的位。例如,

#define API_FULLSCREEN   0x1
#define API_NO_DELAY     0x2
#define API_BLAH_BLAH    0x4

有效并允许您解构函数中的所有标志组合,但是

#define API_FULLSCREEN   0x1
#define API_NO_DELAY     0x2
#define API_BLAH_BLAH    0x3

不是因为API_FULLSCREEN | API_NO_DELAY == API_BLAH_BLAH

从更高的层次来看,一个 flags int 是一个穷人的变量参数列表。如果你考虑使用 C++,你应该将这些细节封装在一个类中,或者至少是一个 std::bitset

【讨论】:

  • 我更喜欢在 C 中工作,所以我想这是我现在必须研究的方式。但是,我将看一下 std::bitset,因为很高兴知道我会假设的这些东西。您的回答很有启发性,谢谢!
  • 我决定将另一个问题标记为答案,因为它提供了一个更具体的示例。真的我想标记两个答案,所以我只想再次感谢你。 :)
  • 您的按位 and 示例不正确。运算符优先级意味着您需要括号才能获得预期的结果:if ( (flags & API_FULLSCREEN) != 0 )
  • @JesseBrands:感谢您的反馈,很高兴能为您提供帮助。
【解决方案2】:

他们在那里做的是使用二进制 OR 将标志组合在一起。

所以实际发生的是:

0x10003003 | 0x10003004 | 0x10003005 == 0x10003007

它仍然是一个参数,但 3 个标志将结合起来为该参数创建一个唯一值,该值可以在函数中使用。

【讨论】:

  • 我认为会是这样,但我想到了几件事。例如,如果两个标志的结果相同怎么办?你能否举一个简单粗暴的实际例子来说明它是如何工作的?我是否必须先计算 -every- 可能性,然后进行切换(标志){ /* case go here */ }
  • @JesseBrands 程序员必须确保自己没有相同的值。所以是的,您必须使用预先计算的标志值进行切换。
  • @JesseBrands:标志当然必须是正交的。对于位向量,这意味着每个标志都设置了一个特定的位(可能还有一些非正交掩码位来指示一组标志中的一个已被使用)。
【解决方案3】:

从函数签名的角度来看,您定义的多参数严格来说是单个参数。 至于基于单个参数处理多个Options,如您所见,bitwise Or Operator 为参数值设置了单个值。然后,函数的主体使用各个位来确定完整的设置。

通常为一个选项分配一个位,它们通常有两个状态(真/假)值。

【讨论】:

    【解决方案4】:

    按位或

    按位 OR 的工作方式与按位 AND 几乎完全相同。唯一的区别是只有两个位中的一个需要为 1,结果中该位置的位为 1。(如果两个位都为 1,则结果在该位置也将为 1。)符号是一根管子:|。同样,这类似于布尔逻辑运算符 ||。

    01001000 | 10111000 = 11111000

    因此 72 | 184 = 248

    所以在你的方法中,它不是一个多参数,它实际上是一个参数。 您可以在 API_FULLSCREEN | 上使用按位或运算API_NO_DELAY | API_BLAH_BLAH 并在方法中传递它。

    【讨论】:

      【解决方案5】:

      这第五个参数通常是一个掩码。它通过定义几个 consts(可能是 enum)来工作,这些 consts 的值是 2 的幂,或者它们的组合。然后使用| 将它们编码为单个值,并使用& 解码。示例:

      #define COLOUR_RED   0x01
      #define COLOUR_GREEN 0x02
      #define COLOUR_BLUE  0x04
      #define COLOUR_CYAN  (COLOUR_BLUE | COLOUR_GREEN) // 0x06
      
      // Encoding
      SetColour(COLOUR_RED | COLOUR_BLUE); // Parameter is 0x05
      
      // Decoding
      void SetColour(int colour)
      {
        if (colour & COLOUR_RED) // If the mask contains COLOUR_RED
          // Do whatever
        if (colour & COLOUR_BLUE) // If the mask contains COLOUR_BLUE
          // Do whatever
        // ..
      }
      

      【讨论】:

      • 这正是我需要知道的。非常感谢,我有点认为是这样的,但我在浏览的任何源代码中都找不到示例!
      【解决方案6】:

      您提供的示例将无法按预期工作。您所做的是为特定选项使用特定位 - 然后 OR 组合

      示例

      #define OPT1 1
      #define OPT2 2
      #define OPT3 4
      

      所以位 1 用于 OPT1,位 2 用于 OPT2 等等。

      所以OPT1 | OPT3 设置位 1 和 3 并给出值 5

      在函数中,您可以使用 AND 运算符测试是否需要特定选项

      所以

      void perform(int opts)
      {
      if (opts & OPT1)
      {
       // Do stuff for OPT1
      }
      ...
      

      【讨论】:

        【解决方案7】:

        该参数通常称为“标志”,包含一组允许值的或组合。

        int flags = API_FULLSCREEN | API_NO_DELAY;
        

        该函数可以接受这个整数参数并像这样提取单个项目:

        int fullscreen_set = flags & API_FULLSCREEN;
        int no_delay_set   = flags & API_NO_DELAY;
        int blah_blah_set  = flags & API_BLAH_BLAH;
        

        为此,必须仔细考虑如何为 API_* 参数选择数值。

        【讨论】:

          【解决方案8】:

          这些参数的值以没有任何重叠的方式定义。像这样的:

          #define A 0x01
          #define B 0x02
          #define C 0x04
          #define D 0x08
          

          鉴于上述定义,您始终可以使用按位 AND 运算符确定上述哪些变量已被 ORed:

          void foo(int param)
          {
              if(param & A)
              {
                   // then you know that A has been included in the param
              }
              if(param & B)
              {
                   // then you know that B has been included in the param
              }
              ...     
          }
          
          int main()
          {
              foo (A | C);
              return 0;
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-02-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多